最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React SetState within a async function - Stack Overflow

programmeradmin0浏览0评论

I'm trying to make a weather application and I am stuck using the async/await function.

I have a function which does a axios call to an api and then I'm trying to set some state variables. The think is that it seems the application is running the setState methods before the promise is resolved.

Here is the method that makes the axios call.

const fetchWeeklyWeather = async () => {

    try {
        let response = await axios.get(url);

        console.log('%cFetch Weekly Weather Response:', 'color: #bada55', response);

        setCurrentWeather(response.data.current);
        setWeeklyWeather(response.data.daily);
        setWeatherAlerts(response.data.alerts);
    } catch (err) {
        // Handle Error Here
        console.error(err);
    }
}

And I call that method on the ponentDidMount like so:

useEffect(() => {
    fetchWeeklyWeather();

    console.log("Current Weather", currentWeather);
    console.log("Weekly Weather", weeklyWeather);
    console.log("Weather alerts", weatherAlerts);

    formatData(weeklyWeather);
}, []);

It is weird because sometimes it works but most of the time it does not. I guess I'm not doing the right think with the async/await. Can anyone give me a hand?

I'm trying to make a weather application and I am stuck using the async/await function.

I have a function which does a axios call to an api and then I'm trying to set some state variables. The think is that it seems the application is running the setState methods before the promise is resolved.

Here is the method that makes the axios call.

const fetchWeeklyWeather = async () => {

    try {
        let response = await axios.get(url);

        console.log('%cFetch Weekly Weather Response:', 'color: #bada55', response);

        setCurrentWeather(response.data.current);
        setWeeklyWeather(response.data.daily);
        setWeatherAlerts(response.data.alerts);
    } catch (err) {
        // Handle Error Here
        console.error(err);
    }
}

And I call that method on the ponentDidMount like so:

useEffect(() => {
    fetchWeeklyWeather();

    console.log("Current Weather", currentWeather);
    console.log("Weekly Weather", weeklyWeather);
    console.log("Weather alerts", weatherAlerts);

    formatData(weeklyWeather);
}, []);

It is weird because sometimes it works but most of the time it does not. I guess I'm not doing the right think with the async/await. Can anyone give me a hand?

Share Improve this question edited Aug 24, 2023 at 21:22 desertnaut 60.4k32 gold badges152 silver badges180 bronze badges asked Feb 9, 2022 at 22:15 Adri FeriaAdri Feria 611 gold badge1 silver badge4 bronze badges 3
  • Yes, you don't use async-await correctly. fetchWeeklyWeather returns a promise, and you don't wait for it. Another problem is what the answer says, state updates can be asynchronous too. You should either access weeklyWeather in another effect, or just return data you need from fetchWeeklyWeather and don't rely on the state here – Estus Flask Commented Feb 9, 2022 at 23:00
  • "you don't use async-await correctly" OPs use of async/await is perfectly fine. "fetchWeeklyWeather returns a promise, and you don't wait for it" pointless. The effect-function can not be async, and even then() is not an option because the state would still not have been updated when that runs. "state updates can be asynchronous too" They are, always! That's why awaiting of fetchWeeklyWeather() is no option. In FunctionComponents there is no notification that tells you when the state has been updated. The Component re-renders, why? Only React knows. – Thomas Commented Feb 10, 2022 at 3:14
  • Thanks guys for you answers. I'll try to fix it this evening and see if i get something. – Adri Feria Commented Feb 10, 2022 at 16:53
Add a ment  | 

3 Answers 3

Reset to default 1
useEffect(() => {
    fetchWeeklyWeather();

    console.log("Current Weather", currentWeather);
    console.log("Weekly Weather", weeklyWeather);
    console.log("Weather alerts", weatherAlerts);

    formatData(weeklyWeather);
}, []);

The callback is only executed on ponent mount (empty dependancy array), so the console.log() statements will only log the initial values of currentWeather, weeklyWeather and weatherAlerts, not the values that are set retrieved by axios.

To fix this you should separate the useEffect callback into multiple callbacks.

// runs on ponent mount
useEffect(() => {
  fetchWeeklyWeather();
}, []);

// runs on ponent mount and whenever currentWeather changes
useEffect(() => {
  console.log("Current Weather", currentWeather);
}, [currentWeather]);

// runs on ponent mount and whenever weeklyWeather changes
useEffect(() => {
  console.log("Weekly Weather", weeklyWeather);
  formatData(weeklyWeather);
}, [weeklyWeather]);

// runs on ponent mount and whenever weatherAlerts changes
useEffect(() => {
  console.log("Weather alerts", weatherAlerts);
}, [weatherAlerts]);

The above should log currentWeather twice. Once with the initial value, and once with the value that is loaded by axios. The same applies for weeklyWeather and weatherAlerts.

Note that formatData() is also called twice. So it must be able to handle the call with the initial data. If this initial data is null you might want to skip the initial call.

const [weeklyWeather, setWeeklyWeather] = useState(null);
//                     initial weeklyWeather value ^^^^

// ...

// runs on ponent mount and whenever weeklyWeather changes
useEffect(() => {
  console.log("Weekly Weather", weeklyWeather);

  // skip the formatData() call if weeklyWeather is null
  if (weeklyWeather) formatData(weeklyWeather);
}, [weeklyWeather]);

The above will skip the formatData() call when weeklyWeather is null (or any other falsy value). Meaning that it will not be called for the initial value, but it is called once the axios response updated the state.

because your function named 'fetchWeeklyWeather' is an async function, you call the 'fetchWeeklyWeather' in your 'useEffect' hook as a sync function, so you can't log right result below.

you should call like this:

useEffect(()=>{
  fetchWeeklyWeather()
  .then(()=>{
  // do the console.log
  })
  .catch(err=>console.error(err))
},[]);

solved this

this.setState((prevState) => {return {page: prevState.page + 1});
发布评论

评论列表(0)

  1. 暂无评论