Hint
The ref pattern solves stale closures in intervals/timeouts. useRef gives you a mutable box (.current) that can be updated without re-creating the effect.
// Stale closure: setInterval always reads count=0
let count = 0;
let staleLog = [];
const id1 = (() => {
const capturedCount = count; // captured at setup
let ticks = 0;
return setInterval(() => {
staleLog.push(capturedCount); // always 0
if (++ticks === 3) clearInterval(id1);
}, 0);
})();
// Ref solution: interval reads from a mutable object
const ref = { current: 0 };
let freshLog = [];
let ticks2 = 0;
const id2 = setInterval(() => {
freshLog.push(ref.current); // always latest
if (++ticks2 === 3) clearInterval(id2);
}, 0);
ref.current = 5;
ref.current = 10;
setTimeout(() => {
console.log(staleLog.join(','));
console.log(freshLog.join(','));
}, 50);0,0,0 10,10,10
Explanation: Stale: capturedCount is frozen at 0. Fresh: ref.current is read at tick time, always sees the latest value (10 by the time ticks run).
Key Insight: The ref pattern solves stale closures in intervals/timeouts. useRef gives you a mutable box (.current) that can be updated without re-creating the effect.