liveBook · Manning

Resource cleanup

As explained in React Quickly, Second Edition

A cleanup function is a function associated with an effect that releases resources or reverses external interactions when the effect is no longer active.

A timer can keep running after its component disappears. In React, an effect can return a cleanup function to stop work it started. React runs that function when the component unmounts; if a dependency changes, it runs the previous cleanup before running the effect again. section 6.1

Stop a stopwatch when it closes

useEffect(() => { const interval = setInterval( () => setSeconds(seconds => seconds + 1), 1000 ); return () => clearInterval(interval); }, []); The effect starts one interval when the stopwatch mounts. The empty dependency array prevents an ordinary re-render from starting another; the returned function clears the interval when the stopwatch unmounts. section 6.1.2

Match cleanup to the interaction:

  • For a pauseable countdown, depend on whether it is running. Clear the old interval when that value changes or the component unmounts; start one only while running. section 6.1.5
  • For a window resize listener, define the callback inside the effect, add it there, and remove that same callback in cleanup. Each component instance adds its own listener, so consider the cost of many instances. section 8.8.1
  • For a slow request, cleanup can abort the request or mark the component as unmounted so a later response does not update its state. section 6.1.2

Cleanup can also stand alone. A dialog may return a function that records its dismissal or restores keyboard focus when it unmounts, without setting anything up in the effect body. This cleanup-only pattern is less common than undoing work an effect started. section 6.1.3

Listing 6.5 An interactive countdown
import { useEffect, useState } from "react";
function Countdown({ from }) {
  const [seconds, setSeconds] = useState(from);        #1
  const [isRunning, setRunning] = useState(false);     #2
  useEffect(() => {
    if (!isRunning) {                                  #3
      return;
    }
    const interval = setInterval(
      () =>
        setSeconds((value) => {                        #4
          if (value <= 1) {
            setRunning(false);                         #5
          }
          return value - 1;                            #6
        }),
      1000
    );
    return () => clearInterval(interval);              #7
  }, [isRunning]);                                     #8
  return (
    <section>
      <h2>Time left: {seconds} seconds</h2>
      <button onClick={() => setSeconds(from)}>        #9
        Reset
      </button>
      <button
        onClick={() => setRunning((v) => !v)}          #10
        disabled={seconds === 0}                       #10
      >
        {isRunning ? "Pause" : "Resume"}               #11
      </button>
    </section>
  );
}
function App() {
  return <Countdown from={10} />;
}
export default App;

The interactive countdown shows why cleanup matters before a new effect, not just when a component disappears: pausing changes a dependency and clears the running interval. section 6.1.5

How React Quickly, Second Edition covers it

How deep it goes
Works through mount, unmount, and dependency-change timing with component examples, including cleanup-only effects.
Examples
Uses a stopwatch, pauseable countdown, window-size display, remote data request, and dialog.
What it assumes
Builds on component state and re-rendering while introducing effect cleanup through concrete UI problems.
What you can do after
Build it from scratch in React components that stop intervals and remove listeners at the right time.
How it connects
Connects useEffect, dependency arrays, component unmounting, timers, event listeners, and asynchronous requests.

Also explained in

Compare how 6 books explain resource cleanup →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of React Quickly, Second Edition. The section links point to the parts of the book it draws on.