Question presented to candidate:
"A setInterval inside a useEffect keeps logging the initial count even after the user has clicked several times. What is happening, and how do you fix it properly?"
What a strong answer should cover:
- Every render creates new function objects that close over that render's props and state. A function stored somewhere long-lived keeps those values forever.
- It is ordinary JavaScript closure behaviour, not a React bug — React just re-runs the function frequently, so it happens constantly.
- The classic triggers: an empty dependency array around a timer or subscription, a callback stored in a ref or passed to a non-React API, and an omitted dependency.
- The fixes, ranked: the functional updater (
setCount(c => c + 1)) reads the latest state from React rather than the closure; correct dependencies so the closure is recreated;useEffectEventfor logic that must read the latest value without being reactive; a ref as the last resort. - The wrong fix: silencing the exhaustive-deps lint rule, which converts a visible bug into a silent one.
- The related trap: a cleanup function should see its own render's values — that is correct, not stale.
Clarifying questions expected:
- "Is the stale value being read, or written? Reading needs a fresh closure; writing usually needs the functional updater."
- "Does the effect genuinely need to re-run when that value changes, or just read the latest?"
Code / implementation expected: Yes — the broken interval and at least two correct fixes.