React.memo, useMemo, useCallback: When They Help (and When They Don’t)

A practical decision framework for memoization in React: when it prevents real work, when it’s wasted complexity, and how to measure.

F

Frontend Interview Team

March 01, 2026

2 min read
React.memo, useMemo, useCallback: When They Help (and When They Don’t)

What you’ll learn

  • The difference between React.memo vs useMemo vs useCallback
  • A decision framework: measure → optimize → re-measure
  • The biggest memoization trap: optimizing renders that are already cheap

The one-liner definitions

  • React.memo(Component): memoizes the result of rendering a component based on props.
  • useMemo(fn, deps): memoizes the result of a computation.
  • useCallback(fn, deps): memoizes a function reference.

All three help only when they prevent expensive work.


The decision framework (senior)

Use memoization when these are true:

  1. You verified the rerenders in the Profiler
  2. The rerender does non-trivial work (heavy compute, big lists, expensive children)
  3. You can keep dependencies correct without creating bugs

If any of those is false, don’t do it.


Example: stable callback to unlock React.memo

const Row = React.memo(function Row({ item, onSelect }: { item: Item; onSelect: (id: string) => void }) {
  return <button onClick={() => onSelect(item.id)}>{item.name}</button>;
});
 
function List({ items }: { items: Item[] }) {
  const [selected, setSelected] = useState<string | null>(null);
 
  const onSelect = useCallback((id: string) => {
    setSelected(id);
  }, []);
 
  return (
    <div>
      {items.map((it) => (
        <Row key={it.id} item={it} onSelect={onSelect} />
      ))}
      <div>Selected: {selected}</div>
    </div>
  );
}

Without useCallback, onSelect changes every render → Row props change → React.memo can’t bail out.


When useMemo is actually useful

  • Expensive derived values:
    • filtering a big list
    • computing a chart series
    • building a search index
const filtered = useMemo(() => {
  return items.filter((x) => x.name.toLowerCase().includes(query));
}, [items, query]);

When it’s not useful

Memoizing cheap computations adds overhead and complexity.


Interview questions

Q1) What’s the difference between useMemo and useCallback?

30-second answer: useMemo memoizes a value, useCallback memoizes a function reference. useCallback(fn) is basically useMemo(() => fn).

Q2) Should you always use React.memo?

30-second answer: No. It’s a tradeoff: extra comparisons and complexity. Use it where it avoids expensive rerenders and you confirmed with the Profiler.


Quick recap

  • Memoization is a tool, not a default
  • Profile first, optimize second
  • Use stable references to enable memo bails