0

I want to use the async/await pattern in my useEffect React hook and I'm getting an ESLint warning that I don't understand.

Here is my code that causes the warning

useEffect(async () => {
 const delay = () => new Promise((resolve) => setTimeout(resolve, 1000));
 async function getData() {
   await delay();
 }
 getData();
}, []);

and the warning:

ESLint: Effect callbacks are synchronous to prevent race conditions. Put the async function inside: (react-hooks/exhaustive-deps)

The answer from a similar question says to add useCallback, but as I have no dependencies, it does not seem to help.

How to fix missing dependency warning when using useEffect React Hook

Here is what that incorrect answer looks like:

    const delay = () => new Promise((resolve) => setTimeout(resolve, 1000));
    async function getData() {
      await delay();
    }
    getData();
  },[]), []);
Pete
  • 3,111
  • 6
  • 20
  • 43

2 Answers2

1

You shouldn't make a usEffect asynchronous. Instead add it to the outside of your useEffect. Here is a Stackoverflow answer that gives one reason why. Instead:

const delay = () => new Promise((resolve) => setTimeout(resolve, 1000));
async function getData() {
    await delay();
}
useEffect(() => { // don't need async here
  getData();
}, []);
graysonmcm
  • 87
  • 2
  • 17
  • Does it matter whether the function is inside our outside useEffect? seems like it would be better inside to maintain minimal scope – Pete Dec 21 '21 at 19:33
  • It makes sense to have it inside, unfortunately React doesn't support it, therefore we're unable to do so. In production applications you are going to be doing it like the example above. To maintain the balance and readability, I would create a reusable function for delay and the time to delay and put that in a utils file. That way you aren't continuously rewriting this component. – graysonmcm Dec 21 '21 at 21:46
  • I believe you but am still not understanding how I might now that React does not support that. Is it a JavaScript thing? a React thing? I see tons of examples with the function inside useEffect but I'm guessing there is something I'm missing as to why that's a bad idea. – Pete Dec 22 '21 at 17:18
  • I could be wrong but to break it down.. ‘useEffect’ is a hook therefore it’s a function that expects a function returned to it. The function it’s expecting is anything we are putting inside it. NOW, if I was to make it async, I would be returning a Promise instead. I think because the way the hook is made, it doesn’t have anything around it that’s waiting for our Promise to finish. – graysonmcm Dec 22 '21 at 18:07
0
useEffect(async () => { // don't need async here
    const delay = () => new Promise((resolve) => setTimeout(resolve, 1000));
    async function getData() {
    await delay();
  }
 getData();
}, []);

The error is telling you not to use async in the call to useEffect() itself. Look here, you have this exact anti-pattern: https://dev.to/danialdezfouli/what-s-wrong-with-the-async-function-in-useeffect-4jne

Also notice how the parentheses in that example are being used to scope the async function as an IIFE so it runs without being explicitly called.

Raydot
  • 1,458
  • 1
  • 23
  • 38