A higher-order component that skips re-rendering if props stay the same. It's like a shield against unnecessary updates.
Every time Parent renders, Child renders too. Even if name is exactly the same.
function Child({ name }) {
console.log("Child rendered"); // Runs every time Parent updates!
return <div>Hello {name}</div>;
}
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
<Child name="Alice" />
</>
);
}Wrap the child in React.memo. Now, if the parent updates but name stays "Alice", the child assumes nothing changed and skips render.
import React, { memo } from 'react';
const Child = memo(({ name }) => {
console.log("Child rendered"); // Only runs if 'name' changes!
return <div>Hello {name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<>
{/* Updating 'count' triggers Parent render... */}
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
{/* ...but Child is memoized and 'name' is static, so it skips! */}
<Child name="Alice" />
</>
);
}React.memo uses shallow comparison. If you pass a new object or function every time, it will think props changed and re-render anyway.
function Parent() {
const [count, setCount] = useState(0);
// 🔴 DANGER: This object is RE-CREATED on every render!
// { name: "Alice" } !== { name: "Alice" } (Referential Equality)
const user = { name: "Alice" };
return (
<>
<button onClick={() => setCount(c + 1)}>Count</button>
{/* React.memo does a shallow check: prevProps.user === nextProps.user */}
{/* Since 'user' is a new reference, the check FAILS and Child re-renders. */}
<MemoizedChild user={user} />
</>
);
}useMemo or useCallback to keep props stable so React.memo can do its job.