Why async callback cannot happen in React useEffect hook?
Tags: webdev, javascript, beginners, react
Published: 2023-05-03 13:24:48

One common issue that developers experience when utilising the ReactJs `useEffect` hook is understanding why async callbacks cannot be utilised within the hook. Let's explore the reasons for this restriction along with some code examples.

## Understanding the useEffect hook

Before we get into why async callbacks can't be utilised in the `useEffect` hook, let's go over what it does. The 'useEffect' hook is used to handle a component's side effects. Side effects are any operations performed by a component that are not related to rendering, such as retrieving data from an API or modifying the page title. 

The `useEffect` hook enables us to perform these side effects in a clean and straightforward manner. When a component mounts, changes, or unmounts, we can define a function to be executed. The "effect" is the function supplied as the first argument to the `useEffect` hook. 

```jsx
import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
```

In the example above, the `useEffect()` hook is used to update the document paragraph tag `<p>` based on the `count` state variable.

## Why async callbacks cannot be used in useEffect

Let's understand the reasons why an asynchronous callback function cannot be called directly from a `useEffect()` hook. This is because the `useEffect` hook expects its effect function to return either a cleanup function or nothing at all. This is due to the `useEffect()` hook's callback function's asynchronous execution and lack of blocking. Therefore, we must follow a specific pattern if we want to call an asynchronous function inside the `useEffect()` hook.

The special pattern is to create a new function that is declared inside the `useEffect()` hook and that contains the async function, and then we can call this new function inside the `useEffect()` hook. Here's an example:

```jsx
import React, { useEffect } from 'react';

function App() {
  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://example.com/data');
      const data = await response.json();
      console.log(data);
    }

    fetchData();
  }, []);

  return <div>Hello World</div>;
}
```

In this example, a brand-new function called "fetchData()" has been developed and is declared inside the "useEffect()" hook. The asynchronous code that we want to execute is contained in this function. Then, to make sure that it only executes once when the component mounts, we call this function from within the "useEffect()" hook and pass an empty dependency array as the second argument.

By using this pattern, we can ensure that the asynchronous function runs as expected without any issues.

## Conclusion

As a result, since useEffect() is an asynchronous, non-blocking function, async callbacks cannot be made directly inside of it. To make sure the asynchronous code executes as intended, we can use a different way that declares a new function inside the "useEffect()" hook.