Effect Cleanup in React

Effect cleanup lets a React effect undo or disconnect whatever it set up. React runs cleanup before the effect runs again when dependencies change, and when the component is removed from the tree.

An effect can create resources or subscriptions that should not remain active forever, such as event listeners, timers, or external connections. To clean them up, return a function from the effect callback.

When an effect has dependencies, React runs the previous cleanup before running the effect again after a dependency change. This prevents the old setup from remaining active alongside the new setup.

React also runs cleanup when the component is unmounted. The cleanup should therefore reverse the setup performed by that particular effect: remove listeners that were added, clear timers that were started, and unsubscribe from subscriptions that were created.

Cleanup is not the place to perform unrelated application work. It should primarily release or disconnect resources established by the effect. In development, React Strict Mode may also perform an additional setup-and-cleanup cycle to expose effects that are not resilient to repeated setup.

Key points

Interview questions

When does a React effect cleanup function run?

Cleanup runs before an effect is executed again when its dependencies have changed. It also runs when the component is removed from the tree. If an effect never re-runs because its dependencies stay unchanged, its cleanup still runs when that component is removed. This makes cleanup the natural place to release resources created by the effect.

How would you clean up a timer created inside an effect?

Create the timer inside the effect and keep its returned identifier. Return a cleanup function that calls the matching clearing API, such as `clearInterval` for an interval. This ensures the timer does not continue running after the effect is no longer active. Keeping setup and cleanup together also makes the ownership of the timer clear.

Why can an effect cleanup run even though the component has not unmounted?

An effect can re-run when one of its dependencies changes. Before React performs the new effect setup, it cleans up the previous effect instance. This allows the old subscription, listener, or connection to be removed before establishing the new one. Therefore, cleanup is not synonymous with unmounting.

What makes an effect cleanup function correct?

A correct cleanup reverses or disconnects the external work established by that effect. For example, an effect that adds an event listener should remove that listener using the appropriate target and function reference. Cleanup should not accidentally remove resources owned by another effect or another component. It should also tolerate the lifecycle patterns in which React invokes setup and cleanup more than once during development.

How would you reason about cleanup when an effect depends on a changing value?

Treat each effect execution as owning the external resource established during that execution. When a dependency changes, React cleans up the previous execution before setting up the next one, so the old resource should be disconnected using the values and references associated with that execution. The dependency list should describe the reactive values used by the effect, while cleanup should release what that particular setup acquired. This prevents stale subscriptions, duplicated listeners, and connections that continue using obsolete configuration.