Effect Dependency Arrays

A React effect dependency array tells React when an effect should be re-run based on the reactive values the effect reads. Correct dependencies keep the effect synchronized with the current component state and props while avoiding unnecessary re-runs.

An effect is created with `useEffect(setup, dependencies)`. The dependency array lists reactive values that the effect uses from the component, such as props, state, or values declared in the component body. React compares each dependency with its previous value using `Object.is` to decide whether the effect needs to run again.

If the dependency array is omitted, the effect runs after every completed render. With an empty array, the effect does not re-run because of later changes to reactive values, although the effect still runs after the initial client-side mount. With specific dependencies, React runs the effect after the initial mount and when at least one listed dependency changes.

Dependencies are about synchronization, not about manually scheduling arbitrary code. For example, if an effect subscribes to a room based on `roomId`, `roomId` belongs in the dependency list so the subscription can be replaced when the room changes. Cleanup from the previous effect runs before React applies the next effect setup when dependencies change.

In modern React, the dependency list should reflect the reactive values used by the effect. The React Hooks lint rules can identify many missing dependencies. If adding a dependency causes unwanted behavior, the usual solution is to restructure the effect or make the dependency stable rather than deliberately hiding the dependency.

Key points

Interview questions

What is the difference between `useEffect(fn)`, `useEffect(fn, [])`, and `useEffect(fn, [value])`?

With no dependency array, React runs the effect after every completed render. With `[]`, it does not re-run because of changes to listed reactive values, since there are none. With `[value]`, React runs it after the initial mount and when `value` changes.

What does the dependency array in `useEffect` do?

It tells React which reactive values the effect depends on. React compares those values with their previous values and re-runs the effect when one changes. The dependency list should include reactive values that the effect reads.

Why should a value used inside an effect usually be included in its dependency array?

The dependency list describes the reactive values that keep the effect synchronized with the component. If a changing value is omitted, the effect can continue using an older value and become stale. Including it lets React re-run the effect when that value changes.

Why can an object or function dependency cause an effect to run repeatedly?

Objects and functions created during rendering can have a new identity on each render even when their contents or behavior appear unchanged. React compares dependencies by identity using `Object.is`, so a newly created object or function is considered different. Depending on the situation, you can move the value inside the effect, derive a primitive dependency, or otherwise stabilize the value.

What happens to an effect's cleanup when a dependency changes?

When React needs to re-run an effect because its dependencies changed, it first runs the cleanup from the previous setup and then runs the new setup. This lets effects release resources such as subscriptions, timers, or connections before establishing replacements. Cleanup also occurs when the component is removed from the tree.