How to use async function in useEffect?
Jasmin Virdi

Jasmin Virdi @jasmin

About: Just another Techie! :)

Location:
Mumbai, India
Joined:
Jan 23, 2020

How to use async function in useEffect?

Publish Date: Jun 20 '22
106 13

In React we all must have used useEffect hook which runs after performing DOM updates and helps us to perform some operation after render.

Before exploring different ways to make async calls inside useEffect let's discuss the problem behind it.

Why we should not use async keyword with useEffect?

Let's take an example to understand this.

const [state, setState] = useState(0)

useEffect(async () => {
    await setState((state) => state + 1);
}, []);
Enter fullscreen mode Exit fullscreen mode

The above piece of code will give error because the async function returns promise and the useEffect doesn't expect callback function to return promise. It should return nothing or a function.

How we can call an asynchronous function inside useEffect? 🤔

In order to make the async call inside useEffect hook we can use the following approaches.

  • Defining async function inside useEffect.
 useEffect(() => {
   const fetchData = async()=> {
     const data = await getData()

     return data
   }
   fetchData()
 }, []);
Enter fullscreen mode Exit fullscreen mode
  • Defining async function outside useEffect.
  const [state, setState] = useState(0)

  const fetchData = useCallback(async()=> {
    const data = await getData();
    setState(data)
  }, [])

  useEffect(() => {
    fetchData()
  }, [fetchData]);
Enter fullscreen mode Exit fullscreen mode

In this case we need to wrap our async function in useCallback to map it with dependency array.

Note - If we do not wrap the function using useCallback hook it will re-render on every update which will result in triggering the useEffect hook again.

I have used these two approaches to use async function with useEffect. Feel free to add any important point or another approach with respect to this topic. 🙌🏻

Happy Learning! 👩🏻‍💻

Comments 13 total

  • Jasmin Virdi
    Jasmin VirdiJun 21, 2022

    Thanks for sharing🙌

    Agreed, this is not recommended. Wanted to throw some light on ways with reasoning.

  • Ivan Jeremic
    Ivan JeremicJun 21, 2022

    You should not do async stuff? So react-query does everything wrong under the hood you say?

  • hbgl
    hbglJun 21, 2022

    Using async from within hooks is completely fine. Yes, it is true that using a hook may not always be the best choice and that you should generally avoid them. However when you need to use an effect and when you need to do something asynchronously, then you should put your async code into the effect handler.

  • hbgl
    hbglJun 21, 2022

    The link you shared has an example on how to asynchronously fetch data inside useEffect: beta.reactjs.org/learn/synchronizi...

  • hbgl
    hbglJun 21, 2022

    Thanks for sharing this very interesting talk. Using the loader api from react-router should definitely be preferred over fetching in the useEffect hook. But I still don't buy the full 'you shouldn't be using async in useEffect' thing because I don't see the fundamental difference between a sync and async effect. An effect is an effect is an effect. I mean look at the VideoPlayer example from the page you linked:

    import { useEffect, useRef } from 'react';
    
    function VideoPlayer({ src, isPlaying }) {
      const ref = useRef(null);
    
      useEffect(() => {
        if (isPlaying) {
          ref.current.play();
        } else {
          ref.current.pause();
        }
      });
    
      return <video ref={ref} src={src} loop playsInline />;
    }
    
    Enter fullscreen mode Exit fullscreen mode

    HTMLMediaElement.play() returns a Promise. Why would it be wrong to make the effect async and await the video being played? React surely doesn't "yell" at you as long you do the proper cleanup.

    • Rense Bakker
      Rense BakkerJun 21, 2022

      You can use async side effects but you would have to use React suspense. Using async side effects without React suspense is an antipattern and should be avoided because A. it makes your app really difficult to debug and B. it has the potential to cause an infinite render loop.

  • kouliavtsev
    kouliavtsevJun 22, 2022

    You can also wrap the fucntion into a IIFE.

    useEffect(() => {
        async () => {
              // Do stuff
        }();
    }, []);
    
    Enter fullscreen mode Exit fullscreen mode
  • Parsa Sabbar
    Parsa SabbarSep 28, 2023

    Check this answer in Stackoverflow:
    stackoverflow.com/questions/533323...

    A simple hook for managing async functions in useEffect.

Add comment