Table of Contents
When you try to execute an async activity inside the React useEffect hook, you might have seen the following warnings:
Effect callbacks are synchronous to prevent race conditions. Put the async function inside:
useEffect function must return a cleanup function or nothing
Consider the following code:
1import { useEffect, useState } from "react"23function App() {4 const [posts, setPosts] = useState([])56 useEffect(async () => {7 try {8 const response = await fetch(`https://jsonplaceholder.typicode.com/posts`)9 const data = await response.json()10 setPosts(data)11 } catch (e) {12 console.error(e)13 }14 }, [])1516 return (17 <div className="App">18 <ul>19 {posts.map(post => (20 <li key={post.id}>{post.title}</li>21 ))}22 </ul>23 </div>24 )25}2627export default App
Here, we are passing async function to the useEffect hook. As you may be aware, async functions return a Promise. However, useEffect expects the function to either return nothing or a clean up function. Hence reacts throws this warning.
There are 2 ways to fix this.
Moving async call to another function
We can define another function inside the useEffect and call it inside the useEffect as shown below:
1import { useEffect, useState } from "react"23function App() {4 const [posts, setPosts] = useState([])56 useEffect(() => {7 const fetchData = async () => {8 try {9 const response = await fetch(10 `https://jsonplaceholder.typicode.com/posts`11 )12 const data = await response.json()13 setPosts(data)14 } catch (e) {15 console.error(e)16 }17 }18 fetchData()19 }, [])20 return (21 <div className="App">22 <ul>23 {posts.map(post => (24 <li key={post.id}>{post.title}</li>25 ))}26 </ul>27 </div>28 )29}3031export default App
Now the function passed to useEffect returns nothing, thus by fulfilling the condition.
Also, you could prevent the race condition by cancelling previous requests.
Using .then() chaining
Instead of using async await syntax, we can use .then()
to resolve the promise:
1import { useEffect, useState } from "react"23function App() {4 const [posts, setPosts] = useState([])56 useEffect(() => {7 fetch(`https://jsonplaceholder.typicode.com/posts`)8 .then(response => response.json())9 .then(data => {10 setPosts(data)11 })12 .catch(e => {13 console.log(e)14 })15 }, [])16 return (17 <div className="App">18 <ul>19 {posts.map(post => (20 <li key={post.id}>{post.title}</li>21 ))}22 </ul>23 </div>24 )25}2627export default App
Now if you run the code, you should not be seeing the warning anymore.
Do follow me on twitter where I post developer insights more often!