React React.memo
Table of Contents + −
In the last lesson, React Rendering Explained, you saw that children re-render whenever their parent does, even with the same props. This lesson uses React.memo to skip those wasted renders on heavy children.
🤔 Why do we need React.memo?
Here’s the pain. A heavy child re-renders every time its parent does, even though nothing about the child changed.
- The parent re-renders for its own reasons, like an unrelated state change.
- The child re-renders too, by default, even with the exact same props.
- If the child is expensive, like a big list or chart, that’s wasted work on every parent render.
- You want the child to say “my props are the same, so I’ll skip this render”.
So React.memo is that skip switch. It makes a component re-render only when its props change, not just because the parent did.
🧩 How to use React.memo
You wrap your component in React.memo. That’s it. The wrapped component now compares its props before re-rendering.
import { memo } from "react";
const Child = memo(function Child({ name }) { console.log("Child rendered"); return <p>Hello, {name}</p>;});Read what the wrapper does.
memo(...)wraps theChildcomponent.- Now before re-rendering, React checks: did
Child’s props change since last time? - If the props are the same, React skips the render and reuses the previous result.
- If a prop changed, it re-renders normally.
So a memoized component re-renders only when its props actually differ, not every time its parent re-renders.
💡 Seeing it work
Let’s see the difference. The parent has its own state, and the memoized child takes a prop that doesn’t change when that state does.
import { useState, memo } from "react";
const Child = memo(function Child({ name }) { console.log("Child rendered"); return <p>Hello, {name}</p>;});
function Parent() { const [count, setCount] = useState(0);
return ( <div> <button onClick={() => setCount(count + 1)}>Count: {count}</button> <Child name="Alex" /> {/* name never changes */} </div> );}Walk through what happens on each click.
- Clicking the button changes
count, soParentre-renders. Childgetsname="Alex", which is the same as before.- Because
Childis wrapped inmemo, React sees the prop is unchanged and skips its render. - So “Child rendered” logs once at the start, and not on the clicks.
Output
Child rendered(click) ... nothing, Child skipped(click) ... nothing, Child skippedWithout memo, “Child rendered” would log on every click. With it, the child stays quiet.
🔍 How the props comparison works
It helps to know how React.memo decides if props changed, because it explains a common gotcha.
React.memodoes a shallow comparison: it checks each prop with===.- For simple values like strings, numbers, and booleans, this works perfectly.
"Alex" === "Alex"is true. - But for objects, arrays, and functions,
===checks identity, not contents. A new object each render looks “changed” even if it holds the same data. - So passing a fresh object or function as a prop defeats
memo, because it looks different every time.
// ❌ a new object every render - memo sees it as "changed" and re-renders anyway<Child user={{ name: "Alex" }} />
// ❌ a new function every render - same problem<Child onClick={() => doStuff()} />memo and fresh objects don't mix
If you pass a new object, array, or function as a prop on every render, React.memo can’t help, because each one looks different. This is exactly where useMemo and useCallback come in: they keep those props stable so memo can do its job. You’ll see this in the next lessons.
⚠️ Common Mistakes
The biggest mistake is wrapping everything in memo by habit, even tiny components where it does nothing useful.
// ❌ pointless on a trivial component - the comparison costs more than the renderconst Label = memo(function Label({ text }) { return <span>{text}</span>;});
// ✅ a plain component is fine for something this cheapfunction Label({ text }) { return <span>{text}</span>;}Keep these in mind.
- Don’t memo trivial components. The props check has its own small cost; for cheap components it’s not worth it.
- Don’t expect
memoto help when you pass fresh objects or functions as props. Stabilize those first. - Don’t reach for
memobefore measuring. Use it on heavy components that re-render needlessly.
✅ Best Practices
A few habits for React.memo.
- Use it on genuinely heavy components that re-render often with the same props.
- Make sure the props are stable: simple values, or objects and functions kept stable with
useMemo/useCallback. - Measure first with
console.logor DevTools, then applymemowhere it actually helps. - Leave cheap components unwrapped; plain is simpler and the re-render costs nothing.
memo is a team player
React.memo works best alongside useCallback and useMemo. Memo skips the render when props are equal; those two hooks keep object and function props equal between renders. Together they actually stop the wasted work.
🧩 What You’ve Learned
- ✅
React.memomakes a component re-render only when its props actually change - ✅ Wrap a component with
memo(...)to turn this on - ✅ It does a shallow
===comparison of props before re-rendering - ✅ Simple props (strings, numbers) compare cleanly; fresh objects/functions always look “changed”
- ✅ Pair
memowithuseMemo/useCallbackto keep object and function props stable - ✅ Use it on heavy components that re-render needlessly, not on every small component
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does React.memo do?
Why: React.memo wraps a component so it skips re-rendering when its props are unchanged, instead of re-rendering just because the parent did.
- 2
How does React.memo compare props?
Why: memo does a shallow comparison, checking each prop with ===. Simple values compare cleanly, but new objects or functions look different every render.
- 3
Why might React.memo NOT prevent a re-render?
Why: memo uses ===, so a fresh object or function passed each render is seen as a different prop. You stabilize those with useMemo/useCallback so memo can work.
- 4
When should you use React.memo?
Why: Use memo on genuinely expensive components that re-render for no reason. On cheap components the comparison costs more than it saves.
🚀 What’s Next?
Now you can stop a heavy child from re-rendering when its props are the same. But that only works if the props stay stable. Next you’ll go deeper into useMemo to keep expensive values and object props stable between renders.