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 3let 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: 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.