Stop 08 · ReactTopics · 12/20

Memoization

Part of the Frontend Developer Roadmap

In short

React re-renders a lot, and usually that's fine. When a slow calculation or a heavy list starts lagging, memoization lets React skip work it has already done.

Caching the result of an expensive computation or a component's render output (`useMemo`, `useCallback`, `React.memo`) so it isn't recalculated unnecessarily.

The jaadu mascot writes an answer instantly at an exam desk with a lightbulb above its head.

Think of it like this

Tables you learnt by heart

Nobody works out 7 × 8 from scratch in the exam hall. You memorised 56 years ago. Memoization saves an answer and reuses it until the inputs change. Ask for 7 × 9 and you work that one out fresh.

Watch it happen

Who re-renders, and who skips

Courses
<input>
Theme button
BigList (memo)
List items

1/6You click Toggle theme. setDark changes state in Courses.

The big ideas

What you need to know

useMemo saves a value

useMemo(() => heavyCalc(list), [list]) recalculates only when list changes.

useCallback saves a function

It keeps the same function between renders. Useful when you pass handlers to memoized children.

memo skips a child

Wrap a component in memo() and it skips re-rendering when its props are the same as last time.

React Compiler can do it for you

The React Compiler adds memoization automatically at build time. Either way, measure first before hand-tuning.

See it in code

Walk through the code

tsx
1import { memo, useMemo, useState } from "react";2const BigList = memo(function BigList({ items }: { items: string[] }) {3  return <ul>{items.map((c) => <li key={c}>{c}</li>)}</ul>;4});5export default function Courses({ all }: { all: string[] }) {6  const [query, setQuery] = useState("");7  const [dark, setDark] = useState(false);8  const filtered = useMemo(() => all.filter((c) => c.includes(query)), [all, query]);9  return (10    <div className={dark ? "dark" : ""}>11      <input value={query} onChange={(e) => setQuery(e.target.value)} />12      <button onClick={() => setDark(!dark)}>Toggle theme</button>13      <BigList items={filtered} />14    </div>15  );16}

1/4memo wraps BigList, so it skips renders when its props haven't changed.

Toggling the theme re-renders Courses, but filtered stays the same array, so memo lets BigList skip its render. Typing changes query, so both update.

Save yourself the pain

Common mistakes

Oops

Wrapping every value in useMemo and every function in useCallback.

Do this instead

Memoization has its own cost. Use it where the Profiler shows a slow render, or let the React Compiler handle it.

Oops

Using memo on a child but passing it a fresh object or arrow function every render.

Do this instead

New objects fail the props check every time. Memoize those props with useMemo or useCallback, or memo does nothing.

Your mission

Find a wasted render

~25 min

Quick check

BigList is wrapped in memo, but the parent passes items={all.filter(...)} without useMemo. Does BigList skip re-renders?

Go deeper

  1. 1Wrap an expensive calculation in `useMemo` and confirm it skips recomputation.
  2. 2Use `React.memo` on a child component to prevent unnecessary re-renders.
  3. 3Learn that premature memoization can hurt more than help — profile first.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge