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)

javascript
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

javascript
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.