【问题标题】:How to set multiple states using one response from axios API call in React如何在 React 中使用来自 axios API 调用的一个响应来设置多个状态
【发布时间】:2021-06-06 02:51:15
【问题描述】:

我在 React 中使用 axios 调用 GET API。后端(Python-Flask)通过写入 return jsonify(animals=animals, cars=cars) 返回数据,这些(汽车和动物)是数组。

响应包含以下格式的数据:

{
  "animals": ["elephant", "lion", "dog"],
  "cars": ["range rover", "fortuner", "land cruiser"]
}

我想使用cars 数组更新cars 状态,并使用animals 数组更新animals 状态。我尝试了以下但只有动物状态正在更新,汽车状态保持为空

应用程序

export default function App() {
    const [animals, setAnimals] = useState([])
    const [cars, setCars] = useState([])

    useEffect(()=> {
        axios.get("http://127.0.0.1:5000/animals_cars").then(
            response=> setAnimals(response.data.animals),
            resp => setCars(resp.data.cars)
        );
        console.log(cars)
        console.log(animals)
    }, []);
}

关于响应的任何帮助,我不知道如何拆分响应以更新不同的状态。

【问题讨论】:

    标签: javascript reactjs axios use-effect use-state


    【解决方案1】:

    .then() 最多接受两个参数; Promise 成功和失败情况的回调函数。在这种情况下,只有在 Promise 被拒绝时才会调用您的第二个回调 (resp => setCars(resp.data.cars))。

    你想使用第一个回调,如果 Promise 被实现,它会被调用。您可以像这样在一个函数中更新两个状态变量:

    export default function App() {
      const [animals, setAnimals] = useState([]);
      const [cars, setCars] = useState([]);
    
      useEffect(() => {
        axios.get('http://127.0.0.1:5000/animals_cars')
        .then((response) => {
          setCars(response.data.animals);
          setAnimals(response.data.cars);
        });
        // state updates are asynchronous
        // state is not updated yet, you can't log these
        // well, you can but chances are it's the default value []
        console.log(cars);
        console.log(animals);
      }, []);
    }
    

    请注意,useState 是异步的。您不能在一行更新状态并假设它已经在下一行更改。您可能会记录未更改的状态。

    【讨论】:

      【解决方案2】:

      当您从 API 加载数据以等待函数完成时,您需要一个异步函数。要在 useEffect 中执行此操作,您需要定义一个新函数并仅在满足条件时执行它。在这种情况下,我创建了一个新的布尔常量 loading,我检查它的值,如果它是真的,我执行 load 函数。函数完成后,我将加载设置为 false,这将阻止加载函数再次执行。这样做的好处是,如果您想再次获取数据,您只需将 loading 设置为 true。

      另一种方法是在 useEffect 之外定义一个带有 useCallback 的记忆加载函数,但我不想让你复杂化。

      一种简洁的书写方式如下。

      export default function App() {
              const [loading, setLoading] = useState(true);
              const [animals, setAnimals] = useState([])
              const [cars, setCars] = useState([])
          
              useEffect(()=> {
                  const load = async () => {
                      const responseData = await axios.get("http://127.0.0.1:5000/animals_cars")
                      .then((response) => {
                        return response.data;
                      })
                      .catch((error) => {
                        console.log(error);
                      });
                      setAnimals(responseData.animals);
                      setCars(responseData.cars);
                      setLoading(false);
                   }
                  if (loading) {
                      load();
                  }
              },[loading]);
          }
      

      【讨论】:

      • 是的,正如我在回答中解释的那样,如果您想触发重新加载,那么拥有这个 loading 状态变量非常有用,例如如果您的 fetch 端点有动态参数,当用户更新它们时,您只需将 loading 设置为 true 并再次执行加载。
      【解决方案3】:

      你可以用这样的功能来解决这个问题

      useEffect(() => { axios.get("http://127.0.0.1:5000/animals_cars")

      .then(函数(响应){ // 处理成功

          setAnimals(response.data.animals);
          setCars(response.data.cars);
        });
      console.log(cars);
      console.log(animals);
      

      }, []);

      【讨论】:

        猜你喜欢
        • 2017-05-02
        • 2021-08-27
        • 2022-11-06
        • 2018-09-15
        • 1970-01-01
        • 2021-02-02
        • 1970-01-01
        • 2021-09-23
        • 1970-01-01
        相关资源
        最近更新 更多