useEffect Cleanup Functions

Understanding Cleanup Functions

Sometimes, an effect needs to be canceled or removed when a component unmounts. Examples include removing event listeners, canceling timeouts, and unsubscribing from data sources. The useEffect cleanup function allows you to do this.

The Problem: Unmanaged Side Effects

Consider this Clock component that updates the time every second:


function Clock() {
  const [time, setTime] = useState(new Date().toLocaleTimeString('en-US'));

  useEffect(()=> {
    setInterval(() => {
      const newTime = new Date().toLocaleTimeString('en-US');
      console.log(`Updated: ${newTime}`);
      setTime(newTime);
    }, 1000);
  }, []);

  return <h1>{time}</h1>;
}
    

This component is then conditionally rendered inside an App component:


function App() {
  const [show, setShow] = useState(true);

  return (
    <>
      <button onClick={() => setShow(prevShow => !prevShow)}>
        Toggle Clock
      

      {show && <Clock />}
    
  );
}
    

When the Clock component unmounts, the interval continues running in the background. When the component is re-mounted, another interval starts, leading to multiple background processes running unnecessarily.

The Solution: Cleanup Functions

To prevent this, return a cleanup function inside useEffect:


function Clock() {
  const [time, setTime] = useState(new Date().toLocaleTimeString('en-US'));

  useEffect(()=> {
    const interval = setInterval(() => {
      const newTime = new Date().toLocaleTimeString('en-US');
      console.log(`Updated: ${newTime}`);
      setTime(newTime);
    }, 1000);

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

  return <h1>{time}</h1>
}
    

Now, whenever Clock unmounts, the interval will be cleared, preventing unnecessary background processes.

How Cleanup Functions Work

Post-Render Cleanup

If a useEffect has no dependency array, it will clean up the previous effect before running again after each render:


useEffect(() => {
  const interval = setInterval(() => {
    console.log("Running...");
  }, 1000);

  return () => {
    console.log("Cleanup executed");
    clearInterval(interval);
  };
});
    

Here, the cleanup runs before every new effect execution, stopping the previous interval before creating a new one.

Key Takeaways

In this reading, you learned:

Further Exploration

To continue learning, visit:

Conclusion

Understanding cleanup functions in useEffect helps prevent unintended side effects and improves performance in React applications.