2

I use the onGetAccount function to get the address of the logged user:

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.

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. 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".
From this I infer that the page is rendered before fetchUserWalletInfo() runs out.

5
  • 2
    You could use the safe navigation operator: <div>{userWalletInfo?.address}</div>. What exactly is your question though? Commented Dec 3, 2020 at 19:27
  • It wokrs, can you explain me why? I mean what is ? for? Commented Dec 3, 2020 at 19:31
  • 1
    ? is the optional chaining operator. It basically works like an if statement. i.e. If userWalletInfo object exists, then retrieve the address property. I've explained the same in my answer below. Commented Dec 3, 2020 at 19:50
  • Also, ? is ES 2020 syntax, therefore you need to make sure you are using Bable in order to polyfill it. If you're using create react app, NextJS or something like that you most likely don't need to worry about this, but if you configured the React app from scratch you need to keep this in mind before shipping it Commented Dec 3, 2020 at 19:52
  • 1
    The ?. operator is more commonly referred as "optional chaining operator". It’s just a syntax sugar that perform a nullish check to the left hand side operand before accessing its property, so you don’t get runtime error like the one you’ve got. Commented Dec 3, 2020 at 19:52

2 Answers 2

4

"TypeError: Cannot read property 'address' of undefined".

What the above error message essentially means is that he userWalletInfo object is undefined and there is no address property on undefined.

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.

Why is userWalletInfo undefined on initial render?

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.

Now, in order to not have this error anymore, all you need to do is have a conditional statement. i.e, you will need to check if the userWalletInfo object exists before trying to retrieve the address property to show on the DOM.

You can do that in multiple ways:

  1. Have a simple if statement
  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).
  3. Use Short-circuiting like user @Shimi has mentioned in her answer.
  4. Let userWalletInfo defaults to empty object. const [userWalletInfo] = useState({}). The effect is similar to optional chaining in that it prevents accessing property of undefined runtime error.

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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 && userWalletInfo.address} </div>

More details:

At the beginning userWalletInfo is undefined, hence trying to access its address will drive the error you are encountering.

The render function is being called (i.e. 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.

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.

1 Comment

It works, can you explain to me why? Or you can link me something to understand better. I am a self taught

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.