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:
- Give
inputData
an initial value with correct data model - Give
url
a fallback value wheninputData
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.