React Memo

React.memo โ€” Preventing Unnecessary Re-renders

React.memo is a Higher-Order Component (HOC) that memoises a component. When a parent re-renders, a memoised child only re-renders if its props actually changed (shallow comparison).

Without memo โ€” The Problem

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

  return (
    <>
      <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
      {/* ExpensiveChart re-renders on EVERY parent render, even though its props never change */}
      <ExpensiveChart data={staticData} />
    </>
  );
}

With memo โ€” The Fix

// Wrap the component in React.memo
const ExpensiveChart = React.memo(function ExpensiveChart({ data, title }) {
  console.log("Chart rendered");
  return <canvas>{/* heavy rendering */}</canvas>;
});

// Now only re-renders if data or title props change

Custom Comparison Function

const UserRow = React.memo(
  function UserRow({ user, onSelect }) {
    return <tr onClick={() => onSelect(user.id)}><td>{user.name}</td></tr>;
  },
  // Return true to SKIP re-render (same as "are props equal?")
  (prevProps, nextProps) =>
    prevProps.user.id === nextProps.user.id &&
    prevProps.user.updatedAt === nextProps.user.updatedAt
);

memo + useCallback

React.memo uses shallow comparison. If you pass a function as a prop, it will be a new reference on every render (breaking memo). Fix it with useCallback.

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

  // Without useCallback: new function reference on every render โ†’ memo is broken
  // With useCallback: same reference โ†’ memo works correctly
  const handleSelect = useCallback((id) => {
    console.log("Selected:", id);
  }, []); // [] = stable forever

  return (
    <>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <UserRow user={user} onSelect={handleSelect} />
    </>
  );
}
TipDon’t wrap every component in React.memo. Profile your app first with React DevTools Profiler, then optimise the components that actually render too often.