useWeb3Contract returns before fetching finishes

Hey there. I’ve encountered a problem with the useWeb3Contract hook and need some help.

I’ve implemented the hook in an exported function, which should return the result (data) of the function call after fetching the data succesfully.

import {useEffect} from "react"
import { useWeb3Contract } from "react-moralis"
import { abi as tokenAbi } from "../../constants/ERC20"

export default function useRetrieveTokenSymbol(address) {
    const {
        runContractFunction: fetch,
        data,
        isFetching,
        isLoading,
    } = useWeb3Contract({
        abi: tokenAbi,
        contractAddress: address,
        functionName: "symbol",
        params: {},
    })

    const retrieve = async () => {
        await fetch()
    }

    useEffect(async () => {
       retrieve()
    }, [])

    if (!isFetching && !isLoading && data) return data
}

This function then gets called in a separate react component, where it should only return the data from the useWeb3Contract hook, which then can be stored in a variable. That looks like that:

export default function TokenSymbol({tokenAddress}) {

const tokenSymbol = useRetrieveTokenSymbol(tokenAddress)

return (
<div>{tokenSymbol}</div>
)

}

tokenSymbol however always is undefined, because the useRetrieveTokenSymbol function returns before finishing fetching the data and then returns an undefined data constant. The conditional if statement gets completely ignored and I simply cannot figure out why.

Any of you guys know a fix to this? Would really appreciate it :slight_smile:

Have you enabled web3 anywhere (enableWeb3() from useMoralis hook)?

You will need web3 enabled to use useWeb3Contract - it uses the provider from your wallet for the correct chain where that contract is and to call the function.

Alternatively consider using useApiContract for read only functions, which uses the Moralis API.

Yes I’ve enabled web3 using the useMoralis() hook in the application.

The code snippets aren’t representation of the full code as that would be too much for a forum post (woking on a big project), so I’ve isolated the code snippet to just the two for demonstration purposes.

But the issue is that the useRetrieveTokenSymbol function returns before the useWeb3Contract hook is done fetching the data. React completely ignores the conditional return statement somehow. Any guess to why?

This modification works on my end as long as I’ve enabled web3 somewhere - also make sure your wallet is on the right chain:

function useRetrieveTokenSymbol(address) {
  const { isWeb3Enabled } = useMoralis();

  const {
    runContractFunction: fetch,
    data,
    isFetching,
    isLoading,
  } = useWeb3Contract({
    abi: tokenAbi,
    contractAddress: address,
    functionName: 'symbol',
    params: {},
  });

  useEffect(() => {
    if (isWeb3Enabled) fetch();
  }, [isWeb3Enabled]);

  return data;
  // or if (!isFetching && !isLoading && data) return data but not needed - when you use the hook, then you handle any data you get (null or valid) appropriately e.g. in a useEffect or rendered directly
}

...

// component
const tokenSymbol = useRetrieveTokenSymbol(
    '0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d'
);

return (
      <div>{tokenSymbol}</div>
      );

Still does not work somehow.
Is there any way to make useRetrieveTokenSymbol wait before returning? So that fetching can finish and only after that the function should return data?

You need your wallet to be on the proper network for useWeb3Contract to work properly. Will suggest using useApiContract as @alex mentioned.

Is there any way to make useRetrieveTokenSymbol wait before returning?

You don’t need to - when you use your hook in <TokenSymbol>, the data will either be valid or not (null). That is one of the main reasons for using hooks like useWeb3Contract, it handles the state/fetching for you.

The issue is somewhere else if you’re not getting a result. Check your wallet chain as mentioned, your options (abi, contractAddress), and test the hook separately (hardcode the address).