简体   繁体   English

异步 function 进入 useEffect 获取组件渲染后的数据

[英]Async function into useEffect fetches data after componet rendering

I use the onGetAccount function to get the address of the logged user:我使用onGetAccount function 来获取登录用户的地址:

const [userWalletInfo, setUserWalletInfo] = useState()

         
  async function onGetAccount() {
    const account = await client.api.asset.getAccount();
    
    return account;
    
  }  
  useEffect(() => {
    async function fetchUserWalletInfo() {
      const address = await onGetAccount();
      
      setUserWalletInfo({
        address: address,
        
      });
    }
    fetchUserWalletInfo();
  }, []);

By doing so I am able to access userWalletInfo.address .通过这样做,我可以访问userWalletInfo.address

The problem is, if I load the component and after that (I mean that while the component run on localhost I edit code in VSCode, I did it to understand if address was set correctly) I edit the js.问题是,如果我加载组件,然后(我的意思是当组件在本地主机上运行时,我在 VSCode 中编辑代码,我这样做是为了了解地址是否设置正确)我编辑js。 file adding:文件添加:

<div> {userWalletInfo.address} </div>

It displays user address correctly, but if I refresh the page I get " TypeError: Cannot read property 'address' of undefined ".它正确显示用户地址,但如果我刷新页面,我会得到“ TypeError: Cannot read property 'address' of undefined ”。
From this I infer that the page is rendered before fetchUserWalletInfo() runs out.由此我推断页面是在fetchUserWalletInfo()用完之前呈现的。

Change your div to only display when userWalletInfo has an address, this will avoid the render function to attempt accessing a property on an undefined object.将您的 div 更改为仅在userWalletInfo具有地址时显示,这将避免渲染 function 尝试访问未定义的 object 上的属性。

<div> {userWalletInfo && userWalletInfo.address} </div>

More details:更多细节:

At the beginning userWalletInfo is undefined, hence trying to access its address will drive the error you are encountering.一开始userWalletInfo是未定义的,因此尝试访问其地址将导致您遇到的错误。

The render function is being called (ie your div) before there is a populated value in userWalletInfo , since the population is happening on an async call, and React render attempts to render the component regardless of async calls that may happen in the background.渲染 function 在userWalletInfo中存在填充值之前被调用(即您的 div),因为填充发生在异步调用上,并且 React 渲染尝试渲染组件而不管后台可能发生的异步调用。

The solution provided works since it provides an extra cautious when trying to display userWalletInfo , it will attempt to access userWalletInfo address only when userWalletInfo isn't undefined, so that solves the failure of the render function before the value is populated.提供的解决方案有效,因为它在尝试显示userWalletInfo时提供了额外的谨慎,它只会在未定义userWalletInfo时尝试访问userWalletInfo地址,从而解决了在填充值之前呈现 function 的失败。

"TypeError: Cannot read property 'address' of undefined". “TypeError:无法读取未定义的属性‘地址’”。

What the above error message essentially means is that he userWalletInfo object is undefined and there is no address property on undefined .上面的错误信息本质上意味着他userWalletInfo object is undefined并且undefined上没有address属性。

The reason for userWalletInfo being undefined is because you are fetching it using an async function, what it means is that when your render() first executes, the value of userWalletInfo is still undefined . userWalletInfo未定义的原因是因为您使用异步 function 获取它,这意味着当您的 render() 第一次执行时, userWalletInfo的值仍然是undefined

Why is userWalletInfo undefined on initial render?为什么在初始渲染时未定义 userWalletInfo?

Because, although you might've made the async function call already, the async functions are not executed on the Javascript main thread, instead they are sent to a WEB API environment as soon as the line of code containing the async function call is executed. Because, although you might've made the async function call already, the async functions are not executed on the Javascript main thread, instead they are sent to a WEB API environment as soon as the line of code containing the async function call is executed.

However, the code outside the async function call is still synchronous, which means it will execute and not wait for the async call to complete and return the data.但是,异步 function 调用之外的代码仍然是同步的,这意味着它将执行而不是等待异步调用完成并返回数据。

Now, in order to not have this error anymore, all you need to do is have a conditional statement.现在,为了不再出现此错误,您需要做的就是有一个条件语句。 ie, you will need to check if the userWalletInfo object exists before trying to retrieve the address property to show on the DOM.即,在尝试检索要在 DOM 上显示的address属性之前,您需要检查userWalletInfo object 是否存在。

You can do that in multiple ways:您可以通过多种方式做到这一点:

  1. Have a simple if statement有一个简单的 if 语句
  2. Use optional chaining operator ?使用可选的链接运算符? like so: userWalletInfo?.address (this just acts like an if-statement. However this is ES 2020 syntax therefore you will need to polyfill if you want to support old browsers).像这样: userWalletInfo?.address (这就像一个 if 语句。但是这是 ES 2020 语法,因此如果您想支持旧浏览器,则需要 polyfill)。
  3. Use Short-circuiting like user @Shimi has mentioned in her answer.像用户@Shimi 在她的回答中提到的那样使用Short-circuiting
  4. Let userWalletInfo defaults to empty object.userWalletInfo默认为空 object。 const [userWalletInfo] = useState({}) . const [userWalletInfo] = useState({}) The effect is similar to optional chaining in that it prevents accessing property of undefined runtime error.效果类似于可选链接,因为它可以防止访问undefined运行时错误的属性。

If you want to know more details about how the Javascript event loop and asynchronous function calls work, please read my answer from here: How Async calls, event loop and callback queue work.如果您想了解有关 Javascript 事件循环和异步 function 调用如何工作的更多详细信息,请从此处阅读我的答案:异步调用、事件循环和回调队列如何工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM