Skip to content
Advertisement

Have checked countless times and can’t figure out where my error is: Uncaught TypeError: Cannot read properties of undefined (reading ‘lat’)

I’ve been playing around with the OpenWeatherMap API to learn to code and have run into a series of TypeError issues popping up in my console. My assumption is that my program is attempting to use data from the API before it is finished fetching, but I have set the fetch functions up to wait until receiving a response to add them to the corresponding state, and have tried many solutions. I have included my App.js code below (with the API Key committed):

function App() {
  // initialize location as UWS (no actual reason)
  const [location, setLocation] = useState("10024");

  // GeoCoder API data to feed into the main weather API
  const [inputData, setInputData] = useState();

  // Main weather API data to feed to UI
  const [apiData, setApiData] = useState();

  // GeoCoder API used for fetching latitude & longitude
  const geoCoder = `http://api.openweathermap.org/geo/1.0/zip?zip=${location},US&appid=${API__KEY}`;

  // Main weather API used for feeding data to the UI (based on lat & lon from geoCoder API)
  const url = `https://api.openweathermap.org/data/2.5/weather?lat=${inputData.lat}&lon=${inputData.lon}&appid=${API__KEY}&units=imperial`;

  // Use user-submitted zip code to fetch latitude & longitude from geoCoder API
  const getInputData = async () => {
    const res = await fetch(geoCoder);
    const jsonRes = await res.json();
    setInputData(jsonRes);
  };

  // Use Zip code from geoCoder API to fetch data from main weather API
  const getApiData = async () => {
    const res = await fetch(url);
    const jsonRes = await res.json();
    setApiData(jsonRes);
  };

  // Initialize website with data
  useEffect(() => {
    getInputData();
  }, []);

  return (
    <div className="container">
      <Title />
      <Search
        location={location}
        setLocation={setLocation}
        getInputData={getInputData}
        getApiData={getApiData}
      />
      <Pinpoint apiData={apiData} />
      <ForecastPreview apiData={apiData} />
      <ForecastDetails apiData={apiData} />
    </div>
  );
}

Additional Context: The apiData state is passed to child components as props and used to render data on-screen from the data stored in apiData.

There are multiple errors in the console just like the one I included in my question’s title, probably all stemming from the same issue.

Have been unable to figure this out for the last three hours. Any and all assistance is extremely appreciated.

Advertisement

Answer

Perhaps try these steps to get the correct url generated with no errors:

  1. Give inputData an initial value with correct data model
  2. Give url a fallback value when inputData is not ready

The following live example will use a public API so there is no need for a key, and it should also work if switched to the project API.

Example: (over simplified live demo on codesandbox)

inputData need correct data model for url to read its properties:

// GeoCoder API data to feed into the main weather API
const [inputData, setInputData] = useState({ lat: null, lon: null });

url need a fallback value when inputData is getting fetched but not ready yet (null is used in here but it can be anything, depending on how it will be used):

// Main weather API used for feeding data to the UI (based on lat & lon from geoCoder API)
const url =
  inputData?.lat && inputData?.lon
    ? `https://api.openweathermap.org/data/2.5/weather?lat=${inputData.lat}&lon=${inputData.lon}&appid=API__KEY&units=imperial`
    : null;

Optional: the data fetching function can be created inside useEffect so it does not need to be added to the dependency array.

// Initialize website with data
useEffect(() => {
  const initInputData = async () => {
    if (!geoCoder) return;
    const res = await fetch(geoCoder);
    if (!res.ok) throw new Error("fetch failed");
    const jsonRes = await res.json();
    setInputData(jsonRes);
  };
  initInputData().catch((error) => console.error(error));
}, [geoCoder]);

There might be other issues needed to be addressed, but hopefully this could at least help generate the correct url without error.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement