let count = 0;
const clicks = [];
// Simulates onClick handler that closes over count
// Bug: handler is created once, closes over count=0
function createHandler() {
const staleCount = count; // captures current value
return function onClick() {
clicks.push(staleCount + 1); // always 0 + 1 = 1
};
}
const handler = createHandler(); // created once
// User clicks 3 times
handler();
handler();
handler();
console.log(clicks.join(','));let count = 0;
const clicks = [];
// Functional update pattern — doesn't need to close over count
function createHandler(getCount, setCount) {
return function onClick() {
setCount(prev => {
const next = prev + 1;
clicks.push(next);
return next;
});
};
}
const handler = createHandler(() => count, (fn) => { count = fn(count); });
handler();
handler();
handler();
console.log(clicks.join(','));Bug: handler closes over staleCount at creation (0). Every click computes 0+1=1 instead of incrementing. The function is never recreated with the new count.
Explanation: Functional update receives the actual current value as prev — never reads from a stale closure. Each click gets the latest count.
Key Insight: Always use setState(prev => prev + 1) when new state depends on previous state. This is especially important when the handler is created once (useCallback, event listeners added in useEffect).