Remembering useEffect Cleanup

A tiny walkthrough of the React pattern I always have to re-derive: subscribe, clean up, and avoid stale work.

useEffect is easy to remember as "run this after render," but the part I always have to slow down for is the cleanup function.

The rule: if an effect starts something that can outlive this render, return a function that stops it.

  1. Import useEffect for the side effect and useState for the value React should re-render with.
  2. The component stores the current browser width in state. The lazy initializer runs once when the component first mounts.
  3. useEffect runs after React has put the component on the page, which is when it is safe to talk to browser APIs like window.
  4. Define the event handler inside the effect so it can use the state setter and so the setup and teardown code share the exact same function reference.
  5. Subscribe to the browser event, then call the handler once so state is correct even if the window changed between the initial render and the effect running.
  6. Return a cleanup function. React calls it before the component unmounts, preventing a leftover listener from trying to update a component that no longer exists.
  7. The empty dependency array means this setup happens once for this component instance. If a value from props or state were used inside the effect, it would usually belong here.
  8. Render stays boring: it just reads state. The effect owns the subscription; the JSX owns the display.

The thing to memorize is not the syntax. It is the lifecycle pair:

  1. Setup: add the listener, start the timer, open the subscription.
  2. Cleanup: remove the listener, clear the timer, close the subscription.

If you can say what your effect starts, you should also be able to say what it stops.