code_learner93
code_learner93

Reputation: 631

Async useEffect does not execute entire body when dependency changes

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?

Upvotes: 0

Views: 1282

Answers (2)

Dilshan
Dilshan

Reputation: 3001

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
}, [])

Upvotes: 1

Michael Brenndoerfer
Michael Brenndoerfer

Reputation: 4086

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])

Upvotes: 2

Related Questions