Navigate
Search topics, hooks, and fundamentals
Since all code runs every render, expensive work re-runs even when its inputs haven't changed.
If you have an expensive calculation in your component — sorting a large array, filtering thousands of records, computing complex data — it runs on every single render, even when the inputs to that calculation haven't changed.
function ProductList({ items }) {
const [search, setSearch] = useState("");
// This sorts on EVERY render — even when you just type
const sorted = [...items].sort((a, b) => a.price - b.price);
return (
<>
<input onChange={e => setSearch(e.target.value)} />
<ul>{sorted.map(item => <li key={item.id}>{item.name}</li>)}</ul>
</>
);
}Every keystroke in the search input triggers a re-render. The sort has nothing to do with the search text, but it runs anyway because React doesn't know the difference.
Type in the text field below. The sort timer shows how many milliseconds the sort takes — even though your typing has nothing to do with the sort. Try increasing the list size to feel the difference.
Sort duration
2.9ms
sorting 5,000 items
useMemo tells React: "only re-run this calculation when its dependencies change."
function ProductList({ items }) {
const [search, setSearch] = useState("");
// Only re-sorts when items actually changes
const sorted = useMemo(
() => [...items].sort((a, b) => a.price - b.price),
[items]
);
return (
<>
<input onChange={e => setSearch(e.target.value)} />
<ul>{sorted.map(item => <li key={item.id}>{item.name}</li>)}</ul>
</>
);
}When to reach for useMemo:
Don't memoize everything — only what's actually expensive. Premature optimization adds complexity without benefit.