【问题标题】:React use state array does not updateReact 使用状态数组不更新
【发布时间】:2020-10-19 20:01:40
【问题描述】:

我正在尝试调用一个 API 来获取天气数据,我需要将每个返回的数据添加到数组状态。但它不起作用,它只显示最后添加的数据。有人可以解释一下为什么会这样并给我一个解决方案

import React, {useEffect, useState} from 'react';
import './App.css';


const data = require('../src/data/Step1'); //Importing json file
const axios = require("axios");
function App() {

    //React Hook to save weather data
    const [weatherData, setWeatherData] = useState([]);

    //UseEffect to call getData function
    useEffect(() => {

        //call getData for each sending city code one by one
        data.List.map(city => getData(city.CityCode));

    }, []);

    //getData function
    async function getData(cityCode) {
        //Axios get request to http get request
        const response = await axios.get('http://api.openweathermap.org/data/2.5/group?id=' + cityCode + '&units=metric&appid=24e343673cb58392072a12e4705b1260');

        //adding each weather object to weather data Array
        setWeatherData([...weatherData,response.data.list[0]]);

    }
    if (weatherData.length > 1) {
        return (
            <div>
                {
                    <div className="container mt-5">
                        {weatherData.map(x => (
                            <div className="row mt-2 ">
                                Id : {x.data.id} {" | "}
                                Name :{x.data.name} {" | "}
                                Description : {x.data.weather[0].description} {" | "}
                                Temperature : {x.data.main.temp}
                            </div>
                        ))}

                    </div>
                }
            </div>
        );
    } else {
        return (
            <div>
                <h1>Loading</h1>
            </div>
        )
    }
}

export default App;

【问题讨论】:

    标签: javascript reactjs axios


    【解决方案1】:

    setState 不会同步发生,因此您无法保证下次调用它时状态会更新。而是尝试以下方法

       async function getData(cityCode) {
    
            const response = await axios.get('http://api.openweathermap.org/data/2.5/group?id=' + cityCode + '&units=metric&appid=24e343673cb58392072a12e4705b1260');
    
            //adding each weather object to weather data Array
            setWeatherData(function (currentWeatherData) {
                return [...currentWeatherData, response.data.list[0]];
              });
    
        }
    

    这是一个 repl 示例 link

    【讨论】:

    • 你是正确的,setState 是异步的,但是使用钩子,效果回调有一个 stale closure 的 weatherData。这就是为什么 linter 会指出这一点,但添加它会使效果运行太多次,因此解决方案是将回调传递给 setWeatherData。所以;您的答案是正确的,但没有正确解释为什么它不起作用。
    【解决方案2】:

    在效果回调中,weatherData 是一个stale closure。也许以下方法会起作用:

    //using useCallback so the dependency of getData to the
    // effect won't cause the effect to run other than when
    // the component mounts
    const getData = React.useCallback(async function getData(
      cityCode
    ) {
      const response = await axios.get(
        'http://api.openweathermap.org/data/2.5/group?id=' +
          cityCode +
          '&units=metric&appid=24e343673cb58392072a12e4705b1260'
      );
      setWeatherData((weatherData) => [
        //using callback so weatherData is not a dependency
        ...weatherData,
        response.data.list[0],
      ]);
    },
    []);
    useEffect(() => {
      //if you don't use the result of a map then use forEach instead
      data.List.forEach((city) => getData(city.CityCode));
    }, [getData]);
    

    您可以将回调传递给状态设置器setWeatherData,它接收当前状态并返回新状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-14
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      • 2019-08-18
      • 2020-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多