MediumStale Closures🐛 Debug Challenge

Event handler reads stale count from first render

Buggy Code — Can you spot the issue?

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(','));

Fixed Code

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 Explained

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).

Practice spotting bugs live →

38 debug challenges with AI hints

🐛 Try Debug Lab