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);
}, []);
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()
}, []);
- Defining async function outside useEffect.
const [state, setState] = useState(0)
const fetchData = useCallback(async()=> {
const data = await getData();
setState(data)
}, [])
useEffect(() => {
fetchData()
}, [fetchData]);
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)
You can also wrap the fucntion into a IIFE.
Thanks for sharing🙌
Agreed, this is not recommended. Wanted to throw some light on ways with reasoning.
There was this talk, "When To Fetch", recently at Reactathon 2022
"You need to initiate fetches before you render"
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 theVideoPlayer
example from the page you linked: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.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.
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.
The link you shared has an example on how to asynchronously fetch data inside useEffect: beta.reactjs.org/learn/synchronizi...
You should not do async stuff? So react-query does everything wrong under the hood you say?
Check this answer in Stackoverflow:
stackoverflow.com/questions/533323...
A simple hook for managing async functions in useEffect.