Home > Mobile >  Async useEffect does not execute entire body when dependency changes
Async useEffect does not execute entire body when dependency changes

Time:06-20

I'm trying to use useEffect with some async functions, however when the dependency in the dependency array changes, only the non async code gets called in useEffect.

    useEffect( async () => {
        console.log(account);
        const web3 = await getWeb3();
        const acc = await loadAcc(web3);
        await loadContract(web3, acc);
    }, [account])

When my account state variable changes, useEffect gets invoked again, but only the console.log(account) statement will get executed.

How should I work around this problem?

CodePudding user response:

The function passed into useEffect cannot be async. You can define an async function inside the useEffect and then use the then/catch syntax.

Further, also pass in all the functions that are defined outside of the useEffect (that you are calling) as a dependency to useEffect

useEffect(() => {

  const myAsyncFunc = async () => {
     console.log(account);
     const web3 = await getWeb3();
     const acc = await loadAcc(web3);
     await loadContract(web3, acc);
  }
  myAsyncFunc.catch(console.error);
       
}, [account, getWeb3, loadAcc, loadContract])

CodePudding user response:

useEffect expected to return either void or a function( the cleanup function ). When you make the function you pass to useEffect as an async, the function will return a promise.

One way to do it is,

    useEffect( () => {
        const init = async () => {
          const web3 = await getWeb3();
          const acc = await loadAcc(web3);
          const res = await loadContract(web3, acc);
          // do something after the async req
        }
        init();
    }, [getWeb3, loadAcc, loadContract])

Or else,

const [web3, setWeb3] = useState(null);
const [acc, setAcc] = useState(null);

useEffect(() => {
  getWeb3();
}, [getWeb3])

useEffect(() => {
  if (!web3) return;
  loadAcc(web3);
}, [web3, loadAcc])

useEffect(() => {
  if (acc && web3) {
   loadContract(acc, web3);
  }
}, [acc, web3, loadContract])

const getWeb3 = useCallback(async () => {
   // do some async work
   const web3 = // async call
   setWeb3(web3)
}, [])

const loadAcc = useCallback(async (web3) => {
  // do some async work
  const acc = // async call
  setAcc(acc);
}, [])

const loadContract = useCallback(async (acc, web3) {
  // do anything
}, [])
  • Related