DEV Community

Cover image for How to use async function in useEffect?
Jasmin Virdi
Jasmin Virdi

Posted on

How to use async function in useEffect?

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! 👩🏻‍💻

Top comments (9)

Collapse
 
kouliavtsev profile image
kouliavtsev

You can also wrap the fucntion into a IIFE.

useEffect(() => {
    async () => {
          // Do stuff
    }();
}, []);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jasmin profile image
Jasmin Virdi • Edited

Thanks for sharing🙌

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

Collapse
 
peerreynders profile image
peerreynders

There was this talk, "When To Fetch", recently at Reactathon 2022

"You need to initiate fetches before you render"

 
hbgl profile image
hbgl

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.

Thread Thread
 
brense profile image
Rense Bakker

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.

Collapse
 
hbgl profile image
hbgl

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 profile image
hbgl

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

Collapse
 
ivan_jrmc profile image
Ivan Jeremic • Edited

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

Collapse
 
parsasabbar profile image
Parsa Sabbar

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

A simple hook for managing async functions in useEffect.