MediumPerformance🐛 Debug Challenge

Context value unstable — all consumers re-render

Buggy Code — Can you spot the issue?

let contextRenders = 0;

// Simulates Provider re-rendering
function Provider(user, children) {
  // Bug: new object every render — all consumers re-render
  const value = { user, logout: () => console.log('logout') };
  return children(value);
}

function Consumer(value) {
  contextRenders++;
  return value.user.name;
}

const user = { name: 'Alice' };

// Simulates 3 parent renders (e.g., parent state changed but user didn't)
for (let i = 0; i < 3; i++) {
  Provider(user, Consumer);
}

console.log(contextRenders); // should be 1, is 3

Fixed Code

let contextRenders = 0;

// Stable value — only recompute when user changes
function memoizeValue(factory, user) {
  if (memoizeValue._prev?.user === user) return memoizeValue._prev.value;
  const value = factory(user);
  memoizeValue._prev = { user, value };
  return value;
}

function Provider(user, children) {
  // Fix: stable reference when user is same
  const value = memoizeValue(
    (u) => ({ user: u, logout: () => console.log('logout') }),
    user
  );
  return children(value);
}

function Consumer(value) {
  contextRenders++;
  return value.user.name;
}

const user = { name: 'Alice' };

for (let i = 0; i < 3; i++) {
  Provider(user, Consumer);
}

console.log(contextRenders);

Bug Explained

Bug: { user, logout: () => ... } creates a new object on every render. Context consumers compare value reference — new value → all consumers re-render, even though user didn't change.

Explanation: memoizeValue returns the same object when user hasn't changed. Same reference → consumers skip re-render on renders 2 and 3.

Key Insight: In real React: ({ user, logout }), [user])}> — wrap context value in useMemo. This prevents all consumers from re-rendering when a sibling state changes.

Practice spotting bugs live →

38 debug challenges with AI hints

🐛 Try Debug Lab