mediumReact#47

Profiling with React.memo

Prompt

Create a list where each item is rendered by a component wrapped in React.memo. Verify that items don't re-render when their props haven't changed (add a console.log in the child).

Solution

const MemoListItem = React.memo(ListItem)

export default function List() {
  const [count, setCount] = useState(0)
  const items = ['Apple', 'Banana', 'Cherry']
  return (
    <View>
      <Text>Count: {count}</Text>
      <Button title="+" onPress={() => setCount(c => c + 1)} />
      {items.map(item => <MemoListItem key={item} label={item} />)}
    </View>
  )
}
Mentor's take

React.memo exists because React's default is brutal: when a parent renders, every child re-renders, props changed or not. Memo converts that O(subtree) cost into a shallow prop comparison — here, pressing "+" re-renders List, but each MemoListItem sees the same label (compared with Object.is) and skips. The console.log in the child is your proof: it fires once per item on mount, then stays silent while the counter climbs.

Two placement details matter. The wrap happens at module scopeReact.memo(ListItem) inside List's body would create a new component type every render, forcing a remount of every row, the exact opposite of the goal. And the memo only holds because the props are primitives: strings compare equal by value under Object.is. Pass an inline object, array, or arrow function and it's a new reference every render — the memo silently never hits, and you pay the comparison plus the render. That's why memo travels with useCallback/useMemo on the props feeding it.

Memo can also hurt: for cheap components the comparison costs more than re-rendering. Profile first (React DevTools Profiler), then memoize proven hot paths — typically list rows and expensive visualizations. The React Compiler automates exactly this, which tells you where the ecosystem is heading.

Red flag: "Wrap everything in memo to be safe." Blanket memoization adds overhead and hides the real problem — usually unstable references or state living too high in the tree.

Say it: "memo is a shallow reference comparison, so it only pays off when the props feeding it are referentially stable — I apply it to profiled hot paths like list rows, not everywhere by default."