How to fix React Hook warnings for async functions in useEffect
Tags: react
Published: 2022-07-27 14:45:43

When you try to execute an async activity inside the React [useEffect](https://www.codingdeft.com/posts/react-useeffect-hook/) hook, you might have seen the following warnings:

`Effect callbacks are synchronous to prevent race conditions. Put the async function inside: `

![return warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x78qa729bqxlgij3wwo1.png) 

`useEffect function must return a cleanup function or nothing`

![async warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhoul0au5lzihruglpe5.png) 

Consider the following code:

```jsx
import { useEffect, useState } from "react"

function App() {
  const [posts, setPosts] = useState([])

  useEffect(async () => {
    try {
      const response = await fetch(`https://jsonplaceholder.typicode.com/posts`)
      const data = await response.json()
      setPosts(data)
    } catch (e) {
      console.error(e)
    }
  }, [])

  return (
    <div className="App">
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

export default App
```

Here, we are passing async function to the useEffect hook. As you may be aware, async functions return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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:

```jsx
import { useEffect, useState } from "react"

function App() {
  const [posts, setPosts] = useState([])

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(
          `https://jsonplaceholder.typicode.com/posts`
        )
        const data = await response.json()
        setPosts(data)
      } catch (e) {
        console.error(e)
      }
    }
    fetchData()
  }, [])
  return (
    <div className="App">
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

export 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](https://www.codingdeft.com/posts/react-prevent-state-update-unmounted-component/#fetch-calls).

## Using .then() chaining

Instead of using async await syntax, we can use `.then()` to resolve the promise:

```jsx
import { useEffect, useState } from "react"

function App() {
  const [posts, setPosts] = useState([])

  useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/posts`)
      .then(response => response.json())
      .then(data => {
        setPosts(data)
      })
      .catch(e => {
        console.log(e)
      })
  }, [])
  return (
    <div className="App">
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

export default App
```

Now if you run the code, you should not be seeing the warning anymore.