React · Frontend system thinking

What is a stale closure in React and how do you fix it?

HardclosuresuseEffectstale stateUpdated Oct 2026
Quiz this track

Short answer

A stale closure captures props or state from an earlier render. The callback keeps reading those old values. Fix it with correct dependencies, a functional state update, a ref or an effect event.

Every render creates new variables and new functions. A callback created during render closes over that render's values. If the callback is registered once and never replaced, it keeps seeing the values from the render in which it was created, even after the component has re-rendered many times.

jsx
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1); // always 0 + 1
    }, 1000);

    return () => clearInterval(id);
  }, []);

  return <p>{count}</p>;
}
The interval closure captured the first render's count. The display updates once and then stops changing.

Fixes, in order of preference

  • Use a functional update when the next state depends on the previous state
  • Add the captured value to the dependency array and let the effect re-subscribe
  • Keep a ref in sync when a long-lived callback needs the latest value without re-subscribing
  • Use useEffectEvent where available to read the latest values from inside an effect without making them dependencies
jsx
useEffect(() => {
  const id = setInterval(() => {
    setCount((current) => current + 1);
  }, 1000);

  return () => clearInterval(id);
}, []);
The functional updater receives the latest state from React, so the interval no longer needs count as a dependency.

A ref can hold the latest callback or value, but do not read or write it during render except for initialisation. Refs are an escape hatch for behaviour that genuinely should not trigger a re-subscription, not a default way to avoid dependencies.

Stale closures are not unique to React. They are a JavaScript scoping behaviour that React makes visible because components re-render and callbacks often outlive the render that created them.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1Why does adding count to the dependency array fix the interval?
  2. 2When is a functional state update the right fix?
  3. 3How can a ref solve a stale closure?
  4. 4What is the difference between a stale closure and a stale prop?

Say it in the interview

A stale closure happens when a callback keeps referencing values from an old render. In React, an interval or event listener set up once can keep reading the initial count. I prefer a functional state update when the new state depends on the old state. If the effect genuinely depends on a value, I add it to the dependencies and make the effect safe to re-run. A ref or an effect event is useful when I need the latest value without re-subscribing.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live React mock interview and get scored feedback on depth, clarity and confidence.