DEV Community

Cover image for Why async callback cannot happen in React useEffect hook?
Sanjampreet Singh
Sanjampreet Singh

Posted on

Why async callback cannot happen in React useEffect hook?

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.

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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:

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>;
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)