The Problem
React.memo prevents re-renders by comparing props with shallow equality. If a prop is an object and only a nested property changes, React.memo sees the same object reference and skips the re-render.
Symptoms
- Component wrapped in React.memo does not update when data changes
- Parent component re-renders but memoized child shows old data
- Works correctly in development but not in production builds
- Only nested object updates fail to trigger re-renders
Real Error Scenario
```javascript const UserCard = React.memo(function UserCard({ user }) { return ( <div> <h2>{user.name}</h2> <p>Status: {user.profile.status}</p> {/* Never updates! */} </div> ); });
function App() { const [user, setUser] = useState({ name: 'John', profile: { status: 'active' } });
const updateStatus = () => { // BAD: Mutates nested object, same reference user.profile.status = 'inactive'; setUser(user); // React.memo sees same user reference, skips re-render };
return <UserCard user={user} />; } ```
How to Fix It
Fix 1: Create New Object Reference (Immutable Update)
const updateStatus = () => {
setUser(prev => ({
...prev,
profile: { ...prev.profile, status: 'inactive' }
}));
};Now user is a new object, and user.profile is also a new object. React.memo's shallow comparison detects the change.
Fix 2: Custom Comparison Function
const UserCard = React.memo(function UserCard({ user }) {
return (
<div>
<h2>{user.name}</h2>
<p>Status: {user.profile.status}</p>
</div>
);
}, (prevProps, nextProps) => {
// Deep comparison for nested objects
return (
prevProps.user.name === nextProps.user.name &&
prevProps.user.profile.status === nextProps.user.profile.status
);
});Note: the function returns true to skip re-render (props are equal) and false to re-render.
Fix 3: Flatten Props
```javascript const UserCard = React.memo(function UserCard({ name, status }) { return ( <div> <h2>{name}</h2> <p>Status: {status}</p> </div> ); });
// Usage: <UserCard name={user.name} status={user.profile.status} /> ```
Primitive props are compared correctly by React.memo's default shallow comparison.
When NOT to Use React.memo
- The component re-renders with different props most of the time
- The comparison cost exceeds the render cost
- Props are complex objects that change frequently
- The component is small and renders quickly
React.memo is an optimization, not a correctness tool. If your app works correctly without it, only add it after profiling confirms a performance benefit.