Why async callback cannot happen in React useEffect hook?
Sanjampreet Singh
Posted on May 3, 2023
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>
);
}
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>;
}
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.
Posted on May 3, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.