ForgeFrontend — Prepare, Practice, Crack
Secure checkout
Lifetime access
Instant PDF download
Free updates forever

Prepare · Practice · Crack

useMemo vs React.memo

Short answer

useMemo is a hook that caches a computed value inside a component so it is not recalculated on every render. React.memo is a wrapper around a whole component that skips its re-render when its props are shallowly equal. One memoises a value, the other memoises a render — and they are usually needed together.

useMemoReact.memo
What it isA hookA higher-order component
What it cachesThe result of a calculationA component's rendered output
Where you write itInside the component bodyAround the component, at export
Recomputes whenA dependency changesA prop is not shallowly equal
Prevents a re-renderNoYes
Prevents a recalculationYesNo
Comparison usedObject.is on each dependencyObject.is on each prop
Typical reason to reach for itAn expensive calculation, or a stable object propA heavy child that re-renders for no reason
Different levels: one wraps a value, the other wraps a component.

The two things being memoised

Both exist because React re-runs a component function on every render, and that function does two kinds of work you might not want repeated: it computes values, and it produces a subtree that React then has to reconcile. useMemo addresses the first, React.memo the second. They sit at different levels, which is why comparing them as alternatives leads people astray — you can need both in the same file, for the same interaction.

Both in one placejsx
1const Chart = React.memo(function Chart({ points }) {
2  return <svg></svg>;
3  // → this whole function is skipped when `points` is
4  //   the same reference as last render
5});
6
7function Dashboard({ rows }) {
8  const points = useMemo(
9    () => rows.map(toPoint).filter(Boolean),   // expensive
10    [rows]
11  );
12  // → recomputed only when `rows` changes; the same array
13  //   reference is handed to Chart on every other render
14
15  return <Chart points={points} />;
16}

Remove the useMemo and React.memo stops working, because rows.map returns a brand-new array every render and a new array is never shallowly equal to the old one. Remove the React.memo and useMemo still saves the calculation, but Chart re-renders anyway. That mutual dependence is the single most useful thing to understand about the pair.

React.memo: skipping a subtree

By default, when a component re-renders, React re-renders all of its children — not because their props changed, but because React does not know whether they did without asking. React.memo is you telling React it is worth asking: before re-rendering this component, compare each of its props to last time, and if they are all the same, reuse the previous output and skip the whole subtree.

What memo actually preventsjsx
1function Parent() {
2  const [count, setCount] = useState(0);
3  return (
4    <>
5      <button onClick={() => setCount(c => c + 1)}>{count}</button>
6      <Heavy title="Report" />
7    </>
8  );
9}
10
11function Heavy({ title }) {
12  console.log("Heavy rendered");
13  return <h2>{title}</h2>;
14}
15// → "Heavy rendered" on every click, even though title never changes
16
17const Heavy = React.memo(function Heavy({ title }) {
18  console.log("Heavy rendered");
19  return <h2>{title}</h2>;
20});
21// → "Heavy rendered" once. Clicks re-render Parent only.

The saving scales with the size of the subtree, not the size of the component. Memoising a leaf that renders one span saves almost nothing. Memoising the root of a list with two hundred rows saves two hundred renders plus the reconciliation of everything they produce, which is why memo belongs at boundaries rather than sprinkled everywhere.

useMemo: caching a value

useMemo runs the function you give it, stores the result, and returns that same result on subsequent renders until one of the dependencies changes. It has two distinct jobs, and mixing them up is the source of most bad memo code: skipping expensive work, and keeping a reference stable so something downstream can rely on it.

The two jobs, side by sidejsx
1// Job 1 — the calculation is genuinely expensive
2const sorted = useMemo(
3  () => hugeList.slice().sort(byPrice),
4  [hugeList]
5);
6// → 5,000-item sort runs once per change of hugeList,
7//   not on every keystroke elsewhere in the component
8
9// Job 2 — the calculation is trivial, the REFERENCE is the point
10const style = useMemo(() => ({ width, height }), [width, height]);
11// → without this, { width, height } is a new object every render,
12//   so <Canvas style={style} /> wrapped in React.memo never bails out
13
14// Not worth memoising — cheaper than the memo bookkeeping
15const total = useMemo(() => a + b, [a, b]);   // ← just write a + b

This is 1 of 75+ questions in the React Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the React Interview Kit → ₹399

Why React.memo so often does nothing

This is the part that costs people real time. React.memo runs a shallow comparison, which means Object.is on each prop. Primitives compare by value and behave intuitively. Objects, arrays and functions compare by identity — and JSX creates fresh ones on every render, so they are never equal to the previous render's version, no matter how identical their contents look.

Four ways to silently defeat memojsx
1const Row = React.memo(RowImpl);
2
3<Row user={user} onSelect={() => pick(user.id)} />
4// → new arrow function every render — memo never bails out
5
6<Row user={user} tags={[]} />
7// → new array literal every render — same problem
8
9<Row user={{ ...user }} />
10// → new object every render
11
12<Row user={user}>{<Badge />}</Row>
13// → children is a new element object every render

The fix is to make each of those references stable at the source: useCallback for the handler, useMemo for the object or array, and a module-level constant for anything that never changes at all. Hoisting a value like an empty array out of the component is free and beats memoising it.

The same list, made memo-friendlyjsx
1const NO_TAGS = [];   // module scope: one array for the app's lifetime
2
3function List({ users, onPick }) {
4  const handleSelect = useCallback(
5    (id) => onPick(id),
6    [onPick]
7  );
8
9  return users.map(u => (
10    <Row key={u.id} user={u} tags={NO_TAGS} onSelect={handleSelect} />
11  ));
12  // → Row now bails out for every user whose object did not change
13}

Where useCallback fits

useCallback is not a third mechanism — it is useMemo specialised for functions. useCallback(fn, deps) is exactly useMemo(() => fn, deps). It exists because passing a stable function reference is such a common need that a dedicated hook reads better than a memo returning a lambda.

Identical behaviourjsx
1const a = useCallback((id) => save(id), [save]);
2const b = useMemo(() => (id) => save(id), [save]);
3// → a and b behave identically; both stay the same reference
4//   until `save` changes
5
6// The difference is only what you get back:
7useMemo(() => compute(x), [x]);      // → the RESULT of calling it
8useCallback(() => compute(x), [x]);  // → the FUNCTION itself, uncalled

So the practical trio is: React.memo to skip a component, useMemo to keep a value or object stable, and useCallback to keep a handler stable. The last two exist mostly in service of the first, or of a hook dependency array — which is a useful way to remember when they earn their place.

The cost side of the trade

None of these is free. React.memo adds a shallow prop comparison before every potential render and keeps the previous element tree alive. useMemo and useCallback each store a value and a dependency array for as long as the component is mounted. When the memoised work is cheap, you have added allocation, comparison and cognitive load in exchange for nothing measurable.

SituationReach forWhy
Child renders a large subtree with stable propsReact.memoSkips the subtree and its reconciliation
Sort or filter over thousands of itemsuseMemoThe calculation dominates the render
Object or array passed to a memoised childuseMemoKeeps the reference stable so memo can bail
Callback passed to a memoised childuseCallbackSame reason, for functions
Value used in another hook's dependency arrayuseMemo / useCallbackStops the effect from firing every render
A sum, a template string, a boolean flagNothingThe memo costs more than the work
A small component that renders a few nodesNothingRendering it is cheaper than comparing props
When each one actually pays for itself.

React 19, the Compiler, and what may become unnecessary

React Compiler analyses your components at build time and inserts memoisation automatically, which removes most of the reason to write useMemo, useCallback and React.memo by hand. In a project where it is enabled and working, hand-written memoisation is mostly noise. It is not a reason to stop understanding the mechanism — the compiler memoises for exactly the reasons described above, and when it bails out on a component, you need to know what it was trying to do.

React 19 also renamed nothing here: React.memo, useMemo and useCallback all still exist and behave as before. What changed around them is that Server Components remove a whole class of client re-renders entirely, which is usually a bigger win than any memoisation you could add.

Can I wrap a component in both React.memo and useMemo?

You would not memoise the same thing twice, but a component wrapped in React.memo commonly contains useMemo calls inside it. What you should not do is useMemo(() => <Child />, deps) as a substitute for React.memo — it memoises the element rather than the component, which works but hides the intent and does not compose.

Does React.memo do a deep comparison?

No, shallow only — Object.is on each prop. You can pass a second argument, a custom areEqual(prev, next) function, to compare differently. Be careful: a deep comparison on a large object can cost more than the render you are skipping, and returning true incorrectly produces a component that never updates.

Does memo stop a re-render caused by state or context?

No. React.memo only guards against re-renders caused by a parent rendering. If the component has its own state, or consumes a context whose value changed, it re-renders regardless of props. That is the second most common reason memo appears not to work.

Is useMemo guaranteed to cache?

No. React documents useMemo as a performance hint, and it may discard cached values — for example to free memory for offscreen content. Never use it for anything whose absence would break correctness; if you need something to run exactly once, that is useEffect or a ref, not useMemo.

What is the difference between React.memo and PureComponent?

They are the same idea in the two component models. PureComponent implements shouldComponentUpdate with a shallow prop and state comparison for classes; React.memo does the shallow prop comparison for function components. Neither compares deeply, and both are defeated by fresh object references.

Frequently asked questions

What is the difference between useMemo and React.memo?
useMemo is a hook used inside a component to cache a calculated value between renders. React.memo is a wrapper placed around a component that skips its re-render when its props are shallowly equal. One memoises a value, the other memoises a render, and they are frequently used together.
Does React.memo cache values?
No. It caches the component's rendered output, keyed on its props. Any values calculated inside the component are recalculated whenever the component does render — caching those is what useMemo is for.
Why is React.memo not working?
Almost always because a prop is a new reference on every render: an inline arrow function, an object or array literal, or JSX passed as children. Shallow comparison sees those as changed. Stabilise them with useCallback, useMemo, or a module-level constant.
When should I use React.memo?
When a component renders a genuinely large subtree, its props are stable, and profiling shows it re-rendering for no reason — typically list rows, charts, editors and heavy panels. Wrapping small components is usually a net loss, because comparing props costs more than rendering them.
When should I use useMemo?
For a calculation heavy enough to show up in a profile, or to keep an object, array or derived value referentially stable for a memoised child, a hook dependency array, or a context value. For simple arithmetic and string building, skip it.
What is the difference between useMemo and useCallback?
useMemo returns the result of calling the function you pass; useCallback returns the function itself without calling it. useCallback(fn, deps) is defined as useMemo(() => fn, deps). Use useMemo for values, useCallback for handlers you pass down.
Does React.memo prevent re-renders from state changes?
No. It only blocks re-renders that come from a parent re-rendering. A component's own useState update, or a context value it consumes changing, re-renders it regardless of how its props compare.
Is it bad to use useMemo everywhere?
Yes, in the ordinary sense that it adds cost and clutter without benefit. Every memo allocates a dependency array and compares it on each render, holds a value in memory, and makes the code harder to read. Reserve it for measured wins and for reference stability.
Can React.memo take a custom comparison function?
Yes — a second argument areEqual(prevProps, nextProps) returning true to skip the render. Note the inverted sense compared with shouldComponentUpdate. Use it sparingly: a deep comparison can cost more than the render, and a wrong true produces a component that never updates.
Does React.memo work with children?
It compares children like any other prop, and JSX children are a new element object on every parent render, so memo usually fails to bail out. Passing children through a memoised wrapper only helps if the parent itself memoises that element.
Does React Compiler make useMemo and React.memo obsolete?
It removes most of the need to write them by hand, because it inserts equivalent memoisation at build time. Understanding the mechanism still matters: you need it to read compiled behaviour, to debug a component the compiler bails out on, and to work in the many codebases that do not have it enabled.
Is React.memo the same as PureComponent?
It is the function-component equivalent. PureComponent gives a class a shallow comparison of props and state; React.memo gives a function component a shallow comparison of props. Both are defeated by newly created object, array and function props.

This is 1 of 75+ questions in the React Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the React Interview Kit → ₹399
Written by Arun Karthikeyan · Last updated

Full kit

React Interview Kit · ₹399

Get it →