HardPerformance🐛 Debug Challenge

Expensive computation in render body — runs every render

Buggy Code — Can you spot the issue?

let computeCount = 0;

function expensiveSort(items) {
  computeCount++;
  return [...items].sort((a, b) => a - b);
}

// Simulates component render function
function render(items, unrelatedState) {
  // Bug: runs on every render — even when only unrelatedState changed
  const sortedList = expensiveSort(items);
  return { sorted: sortedList, state: unrelatedState };
}

const items = [3, 1, 4, 1, 5, 9];

// Render 1: items change
render(items, 'a');
// Render 2: only unrelated state changed, items same
render(items, 'b');
// Render 3: only unrelated state changed, items same
render(items, 'c');

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

Fixed Code

let computeCount = 0;

function expensiveSort(items) {
  computeCount++;
  return [...items].sort((a, b) => a - b);
}

// Simulates useMemo — cache computation, recompute only when items changes
function withMemo(fn, getDeps) {
  let cached = null;
  return function(deps) {
    const current = getDeps(deps);
    if (!cached || cached.dep !== current) {
      cached = { value: fn(current), dep: current };
    }
    return cached.value;
  };
}

const memoizedSort = withMemo(expensiveSort, x => x);

function render(items, unrelatedState) {
  // Only recomputes when items reference changes
  const sortedList = memoizedSort(items);
  return { sorted: sortedList, state: unrelatedState };
}

const items = [3, 1, 4, 1, 5, 9];

render(items, 'a');
render(items, 'b');
render(items, 'c');

console.log(computeCount);

Bug Explained

Bug: expensiveSort is called inside render — it runs on every render, even when items (the actual dependency) didn't change.

Explanation: memoizedSort caches the result keyed by the items reference. Same items reference on renders 2 and 3 → cache hits → computeCount stays at 1.

Key Insight: In React: const sorted = useMemo(() => [...items].sort(), [items]). The computation only re-runs when items changes. Don't put expensive computations directly in render — wrap in useMemo.

Practice spotting bugs live →

38 debug challenges with AI hints

🐛 Try Debug Lab