Lesson 35 of 80
Both hooks skip work by comparing dependencies — the memoization lesson covers that shared mechanism. This one is about the much narrower question of when reaching for either one is actually worth it.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
useMemo and useCallback are close enough in shape that people reach for them interchangeably, but they solve two genuinely different problems. useMemo(fn, deps) skips recomputing a value — you're avoiding real computational work. useCallback(fn, deps) skips creating a new function reference — there's no computation being avoided at all, since defining a function is nearly free; what you're preserving is identity, so something downstream that compares by reference (React.memo, a useEffect dependency array) doesn't see a "change" that isn't real.
That distinction is the entire decision: ask whether you're avoiding expensive work, or avoiding a reference that would otherwise defeat something else's comparison. If it's neither, you don't need either hook.
function ProductList({ products, taxRate }) {
// useMemo: avoiding a real, potentially expensive recomputation
const total = useMemo(
() => products.reduce((sum, p) => sum + p.price * (1 + taxRate), 0),
[products, taxRate]
);
// useCallback: avoiding a *reference change*, not computation —
// this only matters because Row below is wrapped in React.memo
const handleSelect = useCallback((id) => {
console.log("selected", id);
}, []);
return (
<>
<p>Total: {total}</p>
{products.map((p) => (
<Row key={p.id} product={p} onSelect={handleSelect} />
))}
</>
);
}
const Row = React.memo(function Row({ product, onSelect }) {
return <li onClick={() => onSelect(product.id)}>{product.name}</li>;
});
total's computation genuinely costs something proportional to products.length — recomputing it every render, on every keystroke elsewhere in the app, is wasted CPU work with a real, measurable cost. handleSelect costs nothing to create — a function literal is cheap. It's memoized purely so Row, wrapped in React.memo, keeps seeing the same onSelect reference across renders and its shallow prop comparison actually finds a match. Delete React.memo from Row and useCallback here stops doing anything useful at all — there'd be nothing downstream comparing references anymore.
useCallback(fn, deps) is really just useMemo(() => fn, deps). They're built on the same underlying mechanism — useCallback is the specific, more ergonomic case of memoizing a function value instead of a computed one. Knowing this makes the "which one do I reach for" question answer itself: are you memoizing a value, or specifically a function?useEffect dependency is the other real reason to reach for useCallback. If a function is created fresh every render and used inside another component's useEffect deps, that effect re-fires every render — wrapping the function in useCallback with the right deps is what breaks that loop, with no React.memo involved at all.total that's three additions or a handleSelect with no dependencies to check, the comparison can cost more than just redoing the trivial work would have.The memoization lesson covers the shared mechanism underneath both hooks — comparing a dependency array by reference, skipping work if it hasn't changed — and the specific trap of a fresh reference silently defeating React.memo. This lesson narrows in on the decision underneath that: useMemo is for when the work itself is the cost, useCallback is for when only the reference needs to survive for something else's comparison to succeed.