React performs the cleanup when the component unmounts.

I'm not sure where you read this but this statement is incorrect. React performs the cleanup when the dependencies to that hook changes and the effect hook needs to run again with new values. This behaviour is intentional to maintain the reactivity of the view to changing data. Going off the official example, let's say an app subscribes to status updates from a friends' profile. Being the great friend you are, you are decide to unfriend them and befriend someone else. Now the app needs to unsubscribe from the previous friend's status updates and listen to updates from your new friend. This is natural and easy to achieve with the way useEffect works.

 useEffect(() => { 
    chatAPI.subscribe(props.friend.id);

    return () => chatAPI.unsubscribe(props.friend.id);
  }, [ props.friend.id ])

By including the friend id in the dependency list, we can indicate that the hook needs to run only when the friend id changes.

In your example you have specified the array in the dependency list and you are changing the array at a set interval. Every time you change the array, the hook reruns.

You can achieve the correct functionality simply by removing the array from the dependency list and using the callback version of the setState hook. The callback version always operates on the previous version of the state, so there is no need to refresh the hook every time the array changes.

  useEffect(() => {
    const id = setInterval(() => setArray(array => [ ...array, "hello" ]), 3000);

    return () => {
      console.log("unmount");
      clearInterval(id);
    };
  }, []);

Some additional feedback would be to use the id directly in clearInterval as the value is closed upon (captured) when you create the cleanup function. There is no need to save it to a ref.

Answer from Avin Kavish on Stack Overflow
🌐
React
react.dev › reference › react › useEffect
useEffect – React
Your cleanup logic should be “symmetrical” to the setup logic, and should stop or undo whatever setup did: ... Learn how the Effect lifecycle is different from the component’s lifecycle. If your Effect must block the browser from painting the screen, replace useEffect with useLayoutEffect.
🌐
LogRocket
blog.logrocket.com › home › understanding react’s useeffect cleanup function
Understanding React’s useEffect cleanup function - LogRocket Blog
December 16, 2024 - As the name implies, useEffect cleanup is a function in the useEffect Hook that saves applications from unwanted behaviors by cleaning up effects. It allows us to tidy up our code before our component unmounts.
Discussions

Why is the cleanup function from `useEffect` called on every render?
I've been learning React and I read that the function returned from useEffect is meant to do cleanup and React performs the cleanup when the component unmounts. So I experimented with it a bit but... More on stackoverflow.com
🌐 stackoverflow.com
Whats the purpose of cleanup function in useEffect?
The other answers are accurate, but let me provide a real-world example that should make it clearer. Let's say you have a component that you'd like to "listen" to window resizes when it loads: const ResizeAlert = () => { useEffect(() => { const onResize = () => { console.log('resized'); } window.addEventListener("resize", onResize); }, []); return ( // ... ); } Technically, this works just fine. But what happens when ResizeAlert remounts? Then you'd add another event listener on top of the one you already have! If ResizeAlert remounts 20 times, then suddenly you have 20 event listeners in-memory! This could slow your browser to a crawl if ResizeAlert remounts continuously. The solution is to clean up the event listener: useEffect(() => { const onResize = () => { console.log('resized'); } window.addEventListener("resize", onResize); // Clean up event listener return () => window.removeEventListener("resize", onResize); }, []); More on reddit.com
🌐 r/reactjs
6
10
September 20, 2021
`useEffect` cleanup function is being called on mount and not on unmount
I have a database I want to clean up when a user leaves the page. I thought I would do that with a useEffect cleanup function like so: More on github.com
🌐 github.com
2
3
May 30, 2023
Why do we have to return cleanup function from a useEffect that's inside our root (App) component?
It’s because you want to avoid as much as possible writing code that depends on assumptions about how or when a component might mount or not. You want components to be as portable as possible within reason, and that means not making personal judgment calls about whether certain standard practices “make sense” based on the current structure of your app. It’s just easier (and better) to consistently follow the rules rather than try to decide on a case by case basis, especially when the cleanup here is so easy to implement. More on reddit.com
🌐 r/reactjs
13
9
August 28, 2024
🌐
Max Rozen
maxrozen.com › demystifying-useeffect-cleanup-function
Demystifying useEffect's clean-up function - Max Rozen
While React doesn't have a dedicated unmount hook, you can always use useEffect's clean-up function with an empty dependency array:
🌐
Refine
refine.dev › home › blog › tutorials › react useeffect cleanup function
React useEffect Cleanup Function | Refine
September 30, 2024 - The useEffect hook comes with a cleanup function that cleans up effects to prevent memory leaks, which in turn improves the performance of the application.
🌐
Reacttraining
reacttraining.com › blog › useEffect-cleanup
The useEffect cleanup and the two circumstances it's called.
March 21, 2023 - The cleanup function will get called when we "switch" effects. In other words when the dependency array changes and we're about to run the useEffect() function again. React will run the previous effect's cleanup just before we run a new effect.
Top answer
1 of 6
90

React performs the cleanup when the component unmounts.

I'm not sure where you read this but this statement is incorrect. React performs the cleanup when the dependencies to that hook changes and the effect hook needs to run again with new values. This behaviour is intentional to maintain the reactivity of the view to changing data. Going off the official example, let's say an app subscribes to status updates from a friends' profile. Being the great friend you are, you are decide to unfriend them and befriend someone else. Now the app needs to unsubscribe from the previous friend's status updates and listen to updates from your new friend. This is natural and easy to achieve with the way useEffect works.

 useEffect(() => { 
    chatAPI.subscribe(props.friend.id);

    return () => chatAPI.unsubscribe(props.friend.id);
  }, [ props.friend.id ])

By including the friend id in the dependency list, we can indicate that the hook needs to run only when the friend id changes.

In your example you have specified the array in the dependency list and you are changing the array at a set interval. Every time you change the array, the hook reruns.

You can achieve the correct functionality simply by removing the array from the dependency list and using the callback version of the setState hook. The callback version always operates on the previous version of the state, so there is no need to refresh the hook every time the array changes.

  useEffect(() => {
    const id = setInterval(() => setArray(array => [ ...array, "hello" ]), 3000);

    return () => {
      console.log("unmount");
      clearInterval(id);
    };
  }, []);

Some additional feedback would be to use the id directly in clearInterval as the value is closed upon (captured) when you create the cleanup function. There is no need to save it to a ref.

2 of 6
4

The React docs have an explanation section exactly on this.

In short, the reason is because such design protects against stale data and update bugs.

The useEffect hook in React is designed to handle both the initial render and any subsequent renders (here's more about it).


Effects are controlled via their dependencies, not by the lifecycle of the component that uses them.

Anytime dependencies of an effect change, useEffect will cleanup the previous effect and run the new effect.

Such design is more predictable - each render has its own independent (pure) behavioral effect. This makes sure that the UI always shows the correct data (since the UI in React's mental model is a screenshot of the state for a particular render).

The way we control effects is through their dependencies.

To prevent cleanup from running on every render, we just have to not change the dependencies of the effect.

In your case concretely, the cleanup is happening because array is changing, i.e. Object.is(oldArray, newArray) === false

useEffect(() => {
  // ...
}, [array]);
//  ^^^^^ you're changing the dependency of the effect

You're causing this change with the following line:

useEffect(() => {
  const id = setInterval(() => {
    setArray(array.concat("hello")); // <-- changing the array changes the effect dep
  }, 3000);
  myRef.current = id;

  return () => {
    clearInterval(myRef.current);
  };
}, [array]); // <-- the array is the effect dep
🌐
Medium
medium.com › @vishalkalia.er › what-is-the-useeffect-cleanup-function-and-how-it-works-83d8c67a1a10
What is the React useEffect cleanup function, and how it works? | by Vishal Kalia | Medium
December 20, 2022 - The cleanup function is a function that is called when the component is unmounted (i.e., when it is no longer being rendered). It allows you to perform any necessary cleanup tasks, such as cancelling an ongoing API request.
Find elsewhere
🌐
Reddit
reddit.com › r/reactjs › whats the purpose of cleanup function in useeffect?
r/reactjs on Reddit: Whats the purpose of cleanup function in useEffect?
September 20, 2021 -

I know useEffect runs on every render once and also runs according dependency we are providing it, but what dont get is whats the clean up function for? What exactly are we cleaning up also why are we cleaning it?

🌐
Zipy
zipy.ai › blog › understanding-react-useeffect-cleanup-function
Learn all about React useEffect cleanup function
May 27, 2024 - The useEffect cleanup function is invoked when an element that makes use of the useEffect hook is taken from the screen. It is in charge of tidying up any unintended consequences that damage the code.
🌐
React
legacy.reactjs.org › docs › hooks-effect.html
Using the Effect Hook – React
We don’t have to return a named function from the effect. We called it cleanup here to clarify its purpose, but you could return an arrow function or call it something different. We’ve learned that useEffect lets us express different kinds of side effects after a component renders.
🌐
HackerNoon
hackernoon.com › cleanup-functions-in-reacts-useeffect-hook-explained
Cleanup Functions in React’s UseEffect Hook — Explained with examples | HackerNoon
December 1, 2022 - Cleanup functions in React’s useEffect hook allow us to stop side effects that no longer need to be executed in the component.
🌐
Bitstack
blog.bitsrc.io › everything-you-need-to-know-about-useeffects-clean-up-function-in-react-dfa6bc75f4f3
Cleanup Function in useEffect() Hook: All You Need to Know | Bits and Pieces
October 1, 2023 - 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.
🌐
DEV Community
dev.to › otamnitram › react-useeffect-cleanup-how-and-when-to-use-it-2hbm
React useEffect cleanup: How and when to use it - DEV Community
May 14, 2020 - The useEffect hook is built in a way that if we return a function within the method, this function will execute when the component gets disassociated. This is very useful because we can use it to remove unnecessary behavior or prevent memory ...
🌐
Daily Dev Tips
daily-dev-tips.com › posts › react-useeffect-cleanup
React useEffect cleanup
March 20, 2022 - The cleanup can prevent memory leaks and remove unwanted things. Some use-cases for this are: ... Let’s create an example where we have a function that adds something only after a specific time. const [show, setShow] = useState(false); useEffect(() => { let timer = setTimeout(() => setShow(true), 3000); }, []);
🌐
DEV Community
dev.to › werliton › useeffect-with-cleanup-function-in-react-what-it-is-when-to-use-it-and-why-k18
`useEffect` with Cleanup Function in React: What It Is, When to Use It, and Why - DEV Community
June 4, 2025 - A cleanup function is a function returned from within useEffect, and it gets executed either when the component unmounts or before the effect runs again.
🌐
DEV Community
dev.to › edriso › useeffect-cleanup-function-1j8i
useEffect cleanup function?! - DEV Community
December 14, 2025 - You can solve this by uncommenting the cleanup code inside the useEffect. The cleanup function removes the event listener when the component unmounts or before the next effect runs, ensuring that only one event listener is attached.
🌐
Reddit
reddit.com › r/reactjs › why do we have to return cleanup function from a useeffect that's inside our root (app) component?
r/reactjs on Reddit: Why do we have to return cleanup function from a useEffect that's inside our root (App) component?
August 28, 2024 -

https://snipboard.io/QqCHce.jpg

Here's a code I've just come across out of many I've already seen.

So I am aware useEffect's cleanup function runs either when the useEffect has to run for the second, and third and n time and when the component unmounts.

my question is our root component that's App will never unmount and when it does, the user is no longer in our app so why bother cleaning? I can understand it for nested components but not for App's, could someone give me a clear picture on this and maybe an image of what will happen if we dont do this.

Right now I'm doing this in my app just to be super safe but i'm doing it because I see others do and not because I know why we should.

Thanks!

🌐
Aliceiscoding
aliceiscoding.com › the-useeffect-cleanup-function
The useEffect Cleanup Function | by Alice Moretti
September 7, 2022 - The cleanup function runs every time before the useEffect side effect function runs and before the component unmounts.
Top answer
1 of 12
300

You can use more than one useEffect().

For example, if my variable is data1, I can use all of this in my component:

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("data1 update"), [ data1 ] );
useEffect( () => console.log("any update") );
useEffect( () => () => console.log("data1 update or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );
2 of 12
166

Since the cleanup is not dependent on the username, you could put the cleanup in a separate useEffect that is given an empty array as second argument.

Example

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>