Everything You Need to Know About useEffect’s Cleanup Function in React

Jakub Honíšek
Bits and Pieces
Published in
4 min readMar 6, 2023

--

React hooks have become increasingly popular over the last few years, and for a good reason. They simplify code, make it easier to understand and give developers more flexibility in how they write code. However, if you’re new to React hooks, it can be challenging to understand how they work, especially when it comes to useEffect.

UseEffect is a powerful hook that allows developers to manage side effects in their applications. Side effects can include things like fetching data from an API, setting up event listeners, or even subscribing to a WebSocket. These are all actions that can have an impact on the state of your application, and useEffect ensures that they are managed correctly.

When is the cleanup function executed?

One of the things that can be confusing about useEffect is its cleanup function. While it’s commonly known that the cleanup function runs when a component unmounts, it’s less commonly known that the cleanup function also runs before each re-render.

This means that, even though the cleanup function is running in the new render, it still has the old prop values since it was declared in the previous render. For instance, if a component renders multiple times, the previous effect is cleaned up before executing the next effect.

When to use the cleanup function?

The cleanup function can be used for a variety of purposes. One of the most common is to avoid race conditions in async requests. By using the cleanup function to cancel an active request, you can ensure that your application behaves correctly, even when requests return out of order.

import { useState, useEffect } from "react";

function App() {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
let isMounted = true;

const fetchData = async () => {
setIsLoading(true);

try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
const jsonData = await response.json();

if (isMounted) {
setData(jsonData);
setError(null);
}
} catch (err) {
if (isMounted) {
setData(null);
setError(err.message);
}
}

setIsLoading(false);
};

fetchData();

return () => {
isMounted = false;
};
}, []);

if (isLoading) {
return <p>Loading...</p>;
}

if (error) {
return <p>Error: {error}</p>;
}

return (
<div>
<h1>{data ? data.title : "No data available"}</h1>
<p>{data ? data.body : ""}</p>
</div>
);
}

export default App;

Another use case for the cleanup function is to manage subscriptions in your application. For instance, if you’re using a WebSocket to subscribe to real-time data, you’ll need to ensure that you unsubscribe when the component unmounts. This can be done using the cleanup function.

Lastly, while React doesn’t have a dedicated unmount hook, you can use the cleanup function with an empty dependency array to achieve the same effect. This can be useful for cleaning up any resources your component is using when it unmounts.

useEffect(() => {
const handleWindowResize = () => {
console.log('Window resized!');
};

window.addEventListener('resize', handleWindowResize);

return () => {
window.removeEventListener('resize', handleWindowResize);
};
}, []);

Overall, while the cleanup function in useEffect may be confusing at first, it’s an essential feature of the hook that can make your code more robust and reliable. By understanding how the cleanup function works and how to use it effectively, you’ll be able to write more performant and maintainable React applications.

Build React Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--

Experienced front-end developer @ UXF. Typescript, React, Next.js, GraphQL, Tailwind,...