What is a stale closure in React hooks?

Tests closures and hook dependencies. A strong answer defines stale closure as capturing an outdated variable, shows a useEffect interval with stale state, and fixes it with dependencies and cleanup. Red flag: omitting cleanup or using refs blindly.
What's really being asked
This question tests whether you understand that React hooks rely on JavaScript closures and that each render has its own props and state snapshot. The interviewer wants to see if you can explain why a callback created in one render might reference stale values after state updates, whether you know how to use the dependency array and cleanup functions correctly, and whether you understand the mental model of closures over constants rather than live variables.
The full answer
First, define a stale closure as a function that captures a variable from a specific render and does not see subsequent updates because that variable is a constant in the closure scope. Second, provide a concrete code example such as a useEffect with an empty dependency array that calls setInterval to log a count state variable; because the effect runs only once, the interval callback closes over the initial count value and logs it forever. Third, explain the fix by adding the state variable to the dependency array so the effect recreates the interval with the fresh value, and return a cleanup function that clears the interval before re-running to avoid duplicate timers. Fourth, mention that eslint-plugin-react-hooks helps catch missing dependencies automatically and prevents this class of bug.
The mistakes people make
A red flag is suggesting useRef as the primary fix without explaining that refs are mutable and do not trigger re-renders. Another red flag is omitting the cleanup function entirely, which causes interval leaks and duplicate timers. Some candidates incorrectly claim that using the functional update form of setState alone fixes the stale closure in side effects; while functional updates help inside setState, they do not refresh closures inside intervals or event listeners.
What usually comes next
The interviewer may ask how you would handle a rapidly changing value without tearing down and recreating an interval on every render. They might also ask about the difference between closures in useEffect versus useCallback, or how useRef can be used intentionally to hold a mutable value when you truly want to avoid re-subscription.
A concrete example
Imagine a WatchCount component with const [count, setCount] = useState(0) and a useEffect that sets up setInterval to console.log(count) every 2 seconds with an empty dependency array. After the user clicks Increase three times, the UI shows three but the console still logs zero because the interval callback closed over count from the first render. The fix is to add count to the dependency array and return a cleanup function that calls clearInterval(id). This ensures the interval is reset with the current count whenever count changes.
Interview question
In a useEffect with setInterval reading a state variable, which fix removes the stale closure without leaking or duplicating timers?
- a.Store the state in a useRef and read ref.current in the interval with an empty dependency array
- b.Add the state variable to the dependency array and return a cleanup that clears the intervalCorrect
- c.Add the state variable to the dependency array but omit the cleanup to preserve the original timer
- d.Use the functional state updater inside the interval so it always reads the latest value
Why? this is the answer
Adding the state to the dependency array and returning a cleanup that clears the interval recreates the callback with the latest value and prevents leaks. The functional updater distractor is wrong because functional updates only help inside setState, not inside intervals or event listeners where the closure remains stale.
Just read this? Test yourself on what you have been reading.
Read the original → dmitripavlutin.com
- #react
- #hooks
- #closures
- #useeffect
- #interview
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on react — each one lists the topics its interview covers.
See open roles