Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
useMemo memoizes the result of a computation, recomputing it only when its dependencies change. The right use case is a value that is both expensive to compute and used in render — sorting a 10,000-item list, running a complex filter, or deriving a deeply nested structure from props. The common misuse is memoizing trivial computations where the overhead of the dependency comparison on every render exceeds the cost of just recomputing. The other trap: useMemo does not prevent re-renders of the component or its children — for that you need React.memo.
useMemo caches a computed value between renders. The cache is per-component-instance and clears when dependencies change, when the component unmounts, or when React decides to drop it (e.g. offscreen).
sorted directly). Add 50,000 items to the list. Increment the unrelated counter and measure the render time with React Profiler. Observe the sort running on every parent re-render. Re-add useMemo and confirm the performance improvement.useMemo(() => n * 2, [n]) in OverkillComponent to just n * 2. Use React Profiler to compare the render times. They should be identical or the unmemoized version may be faster — confirming that useMemo adds overhead for trivial work.items on every parent render (e.g. <SortedList items={[...data]} />). Watch 'sorting...' fire on every render despite useMemo — because the dependency check sees a new array reference each time. Fix it by stabilizing the reference with useMemo in the parent.import { useState, useMemo } from 'react';
interface Item { id: number; name: string; score: number }
// CORRECT: expensive sort memoized — only re-runs when items or sortKey changes
export function SortedList({ items }: { items: Item[] }) {
const [sortKey, setSortKey] = useState<keyof Item>('score');
const sorted = useMemo(() => {
console.log('sorting...'); // watch how often this fires
return [...items].sort((a, b) =>
a[sortKey] > b[sortKey] ? 1 : -1
);
}, [items, sortKey]);
return (
<div>
<button onClick={() => setSortKey('name')}>Sort by name</button>
<button onClick={() => setSortKey('score')}>Sort by score</button>
<ul>{sorted.map(i => <li key={i.id}>{i.name}: {i.score}</li>)}</ul>
</div>
);
}
// WRONG: memoizing a trivial computation — overhead exceeds benefit
export function OverkillComponent({ n }: { n: number }) {
// Object.is comparison runs on every render regardless
// The "computation" (n * 2) is cheaper than useMemo's bookkeeping
const doubled = useMemo(() => n * 2, [n]); // pointless
return <div>{doubled}</div>;
}