function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
console.log(count); // always logs 0!
setCount(count + 1); // always sets to 1!
}, 1000);
return () => clearInterval(interval);
}, []); // empty deps — closes over initial count=0
return <div>{count}</div>;
}function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
// Fix 1: Use functional update (doesn't need count from closure)
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []); // safe now — no stale closure
// Fix 2 (if you need to read count): add to deps
// useEffect(() => { ... }, [count]); — but this restarts interval each update
return <div>{count}</div>;
}Bug: The effect captures count=0 at mount. The empty dep array means it never re-runs. The interval always uses the stale count=0.
Explanation: Functional updates (setCount(prev => prev + 1)) don't need to read the current state from closure — React provides the latest value as the argument.
Key Insight: Stale closures in React: use functional state updates or add the variable to useEffect dependencies.