useMemo & useCallback
Memoize expensive calculations and stable function references
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
These hooks help avoid unnecessary recomputations and re-renders via , but should only be used when there's a proven performance problem.
useMemo — memoize an expensive calculation result: ``jsx const sortedItems = useMemo( () => [...items].sort((a, b) => a.price - b.price), [items] // only re-sort when items changes );
Without useMemo, the sort runs on every render even if items hasn't changed.
useCallback — memoize a function reference: ``jsx const handleDelete = useCallback( (id) => setItems(prev => prev.filter(i => i.id !== id)), [setItems] // only new reference if setItems changes (it never does) );
Without useCallback, a new function object is created every render. This matters when passing callbacks to memoized child components (React.memo).
React.memo — skip re-render if props haven't changed: ``jsx const Item = React.memo(function Item({ name, onDelete }) { return <li onClick={() => onDelete(name)}>{name}</li>; }); // Only re-renders if name or onDelete changes reference
The rule: don't reach for these by default. Profile first. They add complexity and have their own overhead.
When to use:
useMemo: filtering/sorting large lists, expensive derivationsuseCallback: callbacks passed toReact.memochildren, useEffect dependencies
Examples
useMemo for filtered list
Without useMemo, filtering runs on every render (e.g., unrelated state changes)
function ProductList({ products, searchTerm }) {
const filtered = useMemo(
() => products.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase())
),
[products, searchTerm]
);
return <ul>{filtered.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}useCallback to stabilize a handler
useCallback + React.memo prevents List from re-rendering when count changes
const List = React.memo(function List({ items, onRemove }) {
console.log('List rendered');
return items.map(i => (
<div key={i.id}>
{i.name} <button onClick={() => onRemove(i.id)}>×</button>
</div>
));
});
function Parent() {
const [items, setItems] = useState([...]);
const [count, setCount] = useState(0);
const handleRemove = useCallback(
(id) => setItems(prev => prev.filter(i => i.id !== id)),
[]
);
// Without useCallback, handleRemove is a new function every render
// causing List to re-render even when count changes
return (
<>
<button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
<List items={items} onRemove={handleRemove} />
</>
);
}How well did you understand this?