I have a function that is run when a user clicks a button, when this function is run it gathers data and updates state. I then have another function which runs that uses some of the data that is added to state, the issue is the state is not updating in time so the function is using old data.
async function callWeather() {
const key = "";
// Get location by user
let location = formData.location;
// Url for current weather
const currentWeatherUrl = `https://api.openweathermap.org/data/2.5/weather?q=${location}&units=metric&appid=${key}`;
// Get the current weather
const currentWeatherResponse = await fetch(currentWeatherUrl);
if (!currentWeatherResponse.ok) {
// Return this message if an error
const message = `An error has occured: ${currentWeatherResponse.status}`;
throw new Error(message);
}
const weatherDataResponse = await currentWeatherResponse.json();
// Update state with data
setWeatherData(weatherDataResponse);
}
async function callForcast() {
const key = "";
// Get lat & lon from the previous data fetch
const lon = weatherData.coord.lon
const lat = weatherData.coord.lat
// Get forcast data
const forcastWeatherUrl = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&units=metric&appid=${key}`
const forcastWeatherResponse = await fetch(forcastWeatherUrl);
if (!forcastWeatherResponse.ok) {
const message = `An error has occured: ${forcastWeatherResponse.status}`;
throw new Error(message);
}
const forcastDataResponse = await forcastWeatherResponse.json();
// Update state with the forcast data
setForcastData(forcastDataResponse);
}
This then runs with the onClick calling both functions
function callWeatherAndForcast() {
callForcast();
callWeather();
}
use 'await' before calling callForcast so the second function (callWeather) does'nt get called immediately after calling first function.
async function callWeatherAndForcast() {
await callForcast();
callWeather();
}
also as @tromgy mentioned in the comments, React state updates are not immediate, try calling callWeather function inside a hook which has a dependency on forcastData state
Are you using FunctionComponent or Classes ?
Also, keep in mind that updating the state will trigger a rerendering. This means that:
For helping you correctly, I need to know if you use FunctionComponent or Class and get the whole Function/Class.
Edit: based on the fact that you're using FunctionComponent.
In order to archive what you want, you need to use hooks.
Hooks are the way to handle a function component lifecycle.
For your problem, you'll need useState, useCallback hooks.
export const DisplayWeather = () => {
const [forecast, setForecast] = useState();
const [weather, setWeather] = useState();
const [error, setError] = useState();
const onSubmit = useCallback(async () => {
getWeather();
getForecast();
}, [forecast, weather]);
const getWeather = useCallback(async () => {
const key = "";
const location = formData.location;
const currentWeatherURL = `https://api.openweathermap.org/data/2.5/weather?q=${location}&units=metric&appid=${key}`;
const apiResponse = await fetch(currentWeatherURL);
if(!apiResponse.ok){
const message = `An error has occured: ${apiResponse.status}`;
setError(message);
} else {
const weatherData = apiResponse.json();
setWeather(weatherData);
}
}, [formData]);
const getForecast = useCallback(async () => {
const key = "";
const lon = weather.coord.lon;
const lat = weather.coord.lat;
const forecastWeatherUrl = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&units=metric&appid=${key}`
const apiResponse = await fetch(forecastWeatherUrl);
if(!apiResponse.ok) {
const message = `An error has occured: ${apiResponse.status}`;
setError(message);
} else {
const forecastData = apiResponse.json();
setForecast(forecastData);
}
}, [weather]);
if(error){
return (
<p>Error: {error}</p>
)
}
return (
<p>Forecast data</p>
<p>{forecast.data.temperature}</p>
<p>Weather data</p>
<p>{weather.data.temperature}</p>
);
}
In the code above, I set 2 state variables (weather & forecast) and create 3 functions.
The onSubmit function is called when the user click. His callback depend on two variables (weather & forecast) which are referenced in the dependency array (the [] after the callback)
The getWeather function is called before getForecast because the result of the getForecast function depends on the weather state. That's why you have weather in the getForecast callback dependency array. It tells getForecast that when the value of weather change, it needs to re-render.
Note that i've added formData into the dependency array of getWeather otherwise, when the user click, the getWeather function won't get any value from formData.
Note: it is not a working example, just a simple explanation. You can find more infos here: Hooks Reference useCallback Reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With