【问题标题】:Printing variable after fetching data from API gives empty and after that filled value is printed从 API 获取数据后打印变量为空,然后打印填充的值
【发布时间】:2021-01-12 06:08:10
【问题描述】:

假设我在 React 中获取了一个 API,并在数据列表中设置了它的值

const [dataLists, setdataLists] = useState([])

const fetchAPI = () => {
        axios.get(`/api/fetchDetails/fetchData/${comp_id}`).then((data) => {

            setdataLists(data.data);
        }).catch(error => {
            console.log(error);

        })
    }

useEffect(() => {
        fetchAPI()
    }, [])

console.log(dataLists) # This prints first empty array and then the value is printed though I have 
                         called after data has been set.

我想在调用 fetchAPI 函数并设置值后打印数据非空数组。由于空数组,我使用 dataLists 执行的任何操作都会给出未定义的错误,因为在开始时它会得到空数组,之后只会得到值。

如果需要更多信息,请告诉我。

【问题讨论】:

  • Axios 异步工作,设置数据集的一些默认值并在使用前检查数据集是否设置如下 if(dataset.length!=0)
  • useEffect 仅在安装组件后调用。因此,您的第一个 console.log 将始终打印您传递给 useState 的初始状态。
  • @NareshTeli 抱歉,我不确定我是否听懂了您所说的。你能不能更清楚一点。什么可以设置为默认值?你的目的是什么?
  • @ShriharshaKL 那么你有什么目的需要做。因为我到现在都这样工作,所以我有点迷茫
  • 由于代码是异步的,所以会先触发get函数,然后执行console.log语句,如果要打印,在axios.get()里面加上console.log .then((data)=>{console.log(data.data))}

标签: javascript node.js reactjs react-hooks


【解决方案1】:

从您的代码中可以清楚地看出,您在 useEffect() 之外的组件内执行 console.log(dataLists)

注意useEffect() 是在组件的JSX 被渲染之后调用的。因此,作为组件(本质上是一个函数),当它运行时,它会传递这行代码 console.log(dataLists),并且由于您将 dataListsstate 变量设置为 empty array,它最初会输出一个空数组。

const [dataLists, setdataLists] = useState([]);

因此,您必须创建良好的代码结构。例如添加loading 状态和error 状态,并相应地处理 JSX。

使用以下结构会有所帮助:

import React, { useEffect, useState } from "react";

const url = "https://api.github.com/users/emmeiwhite";

// Conditional Renders
const FetchingAndShowing = () => {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);
  const [user, setUser] = useState({});

  useEffect(() => {
    fetch(url)
      .then((response) => {
        if (response.status >= 200 && response.status < 300) {
          setLoading(false);
          return response.json();
        } else {
          throw new Error("Error: Could not fetch the data");
        }
      })
      .then((data) => {
        console.log(data);
        setUser({ ...user, ...data });
      })
      .catch((error) => {
        setError(true);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <h3>Loading ...</h3>;
  }

  if (error) {
    return <h3>Error in the API call itself ...</h3>;
  }

  return (
    <div>
      <div>
        <h1>Name: {user.login}</h1>
        <img src={user.avatar_url} />
      </div>
    </div>
  );
};
export default FetchingAndShowing;

【讨论】:

  • 感谢您的回复,是的,这是我使用加载和错误调用 api 的方法。而且我可以使用@zahra zamani 建议的 if else 方法在一定程度上解决我的查询。但是,当我设置 if dataList.length > 0 并执行 console.log 时,它会重新渲染两次,当我在 if 条件内执行 setState 时,它​​会给我错误:重定向过多。而且在useEffect中我使用的是空的[],所以它应该渲染一次。你能帮我看看怎么做吗?您是否理解我要说的内容或者我应该编辑问题本身。
  • 我很乐意提供帮助 :) 但我需要自己检查问题。想一想创建一个代码沙盒项目。添加您的组件....使用我上面的 API 进行测试并与我分享链接... :-) 我会帮忙的,别担心...我喜欢 ReactJS
  • @SangamBasnet:亲爱的朋友!我会让你知道,除非我知道你的代码中发生了什么,否则我无法判断错误是什么。其次是异步世界是一个不同的世界 - 我们不知道何时可以获得可用数据。如果您将代码和框链接发送给我,您的查询将得到解决:) 我保证
  • 抱歉 Imran 让您久等了.....非常感谢您的支持。对此,我真的非常感激。 :) 这是代码和框codesandbox.io/s/black-brook-8wfbr?file=/src/App.js 的链接我已经评论了我面临问题的哪一行。如果您需要任何进一步的信息,请告诉我。 :)
  • 兄弟你有没有想出解决方案或者你对我有什么建议。请务必告诉我。
【解决方案2】:
 const fetchAPI =async () => {
     await   axios.get(`/api/fetchDetails/fetchData/${comp_id}`).then((data) => {

            setdataLists(data.data);
            console.log(data.data); #They both will work
            console.log(dataLists); #They both will work
        }).catch(error => {
            console.log(error);

        })
    }

并在打印数据列表之前应用条件,例如:

{dataLists &&  dataLists.length !=0 ? ///The codes you want to use :[]}

【讨论】:

  • 所以我唯一想到的就是使用条件..
  • 您的意见是完全正确的,但是因为当我尝试将其值设置为另一个变量或使用 setState 时它会渲染两次,所以它给了我错误:重新渲染太多。
  • @zahrazamani:您好!希望你做得很好!仅供您参考和学习目的... async-await 如何解决 OP 的这个问题 :) !这是 OP 解决问题所需的更好的代码结构......因为外部异步函数 console.log() 总是会在 useEffec() 之前被调用......费用 AmaanilLah
  • 嗨。谢谢您的解释
  • @zahrazamani:欢迎你 :) 是的,你有一个祝福的名字! Zahra :-) 我们非常尊重我们敬爱的先知 (AS) 的纯洁女儿 (AS) :)
【解决方案3】:

看到您的问题,您在异步函数之外调用了 log 方法,因此它首先执行它,然后在设置数据后再次执行它,如果您想查看数据,我建议您遵循这种方法,因此确保 log 方法仅在我们获取数据之后调用,而不是在它之前调用。

const [dataLists, setdataLists] = useState([])

const fetchAPI = () => {
        axios.get(`/api/fetchDetails/fetchData/${comp_id}`).then((data) => {

            setdataLists(data.data);
            console.log(data.data); #They both will work
            console.log(dataLists); #They both will work
        }).catch(error => {
            console.log(error);

        })
    }

useEffect(() => {
        fetchAPI()
    }, [])

编码愉快:)

因此,根据您在 cmets 中的问题,仅渲染一次 useEffect 我们可以执行以下操作

const [location, setLocation] = useState("you route.com/somepath")

useEffect(() => {
        fetchAPI()
    }, [location])

这个概念是,只有当我们来到页面时,我们才会渲染 useEffect() 或者只有当我们重新加载它们才会被触发 我已经在我的一个 React 应用程序中使用了它,它们的性能也很好,请尝试一下 :)

【讨论】:

  • 感谢您的回复,但我想在外面打印它的原因是因为我必须使用 dataLists 并且因为它给了我空然后填充的值。 @Zahra zamani 建议我使用 if 条件,但这里的问题是当我尝试使用 setValue 时,它​​给我的错误太多重定向,因为 useEffects 渲染两次
  • 那么你知道如何渲染useEffects一次
  • 是的,我们可以做到,我会相应地更新答案
猜你喜欢
  • 1970-01-01
  • 2020-11-30
  • 2011-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2012-11-01
相关资源
最近更新 更多