React.memo

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

React.memo

React.memo is a Higher-Order Component (HOC) used to optimize performance by preventing unnecessary re-renders of functional components.

Default Rendering Behavior

By default in React, if a parent component re-renders, all of its children will re-render, regardless of whether their props changed.

function Parent() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      {/* Even though Child gets no props, it re-renders every time count changes! */}
      <Child /> 
    </div>
  );
}

Using React.memo

If the <Child /> component contains a complex UI (like a large graph or a heavy table), those unnecessary re-renders will cause performance lag.

You can fix this by wrapping the component in React.memo().

import { memo } from 'react';

const Child = memo(function Child(props) {
  // Heavy rendering logic here...
  return <div>I only re-render if my props change!</div>;
});

When you wrap a component in memo, React will compare the new props with the old props before attempting to re-render.

  • If the props are exactly the same, React skips the render phase for that component and reuses the last rendered result.
  • If the props have changed, the component re-renders normally.

The Referential Equality Trap

React.memo does a shallow comparison of props using Object.is.

This means it works perfectly for primitive props (strings, numbers, booleans). However, if you pass an object, array, or function as a prop, React.memo will often fail to optimize anything, because a new reference is created on every render of the parent.

function Parent() {
  const [count, setCount] = useState(0);

  // ❌ BAD: This object gets a brand new memory address on every render.
  // React.memo will think the props changed, and re-render the child anyway!
  const config = { theme: 'dark' };

  // ❌ BAD: This function gets a new memory address on every render.
  const handleClick = () => console.log('Clicked');

  return (
    <MemoizedChild config={config} onClick={handleClick} />
  );
}

To make React.memo work correctly with objects and functions, you must combine it with useMemo and useCallback in the parent component to stabilize those references.

Custom Comparison Function

If a shallow comparison isn’t enough, React.memo accepts a second argument: a custom comparison function. It works similarly to shouldComponentUpdate in old class components, but the logic is reversed (it returns true if props are equal).

const MemoizedComponent = memo(MyComponent, (prevProps, nextProps) => {
  // Return true if passing nextProps to render would return
  // the same result as passing prevProps to render,
  // otherwise return false
  return prevProps.user.id === nextProps.user.id;
});

Interview Questions

Q: What does React.memo do?
A: It is a Higher-Order Component (HOC) that prevents a functional component from re-rendering if its incoming props have not changed. It does this by performing a shallow equality comparison on the previous props versus the new props.