🎯 React.memo, useCallback, useMemo
reactadvanced

🎯React.memo, useCallback, useMemo

Three tools to prevent unnecessary re-renders: React.memo (component), useCallback (function), useMemo (value). All use reference equality and shallow comparison.

Memory Trick

memo=component, useCallback=function, useMemo=value. Memoize what changes your children's references.

Log in to track your mastery & progress

1️⃣ The Three Tools

ToolWhat it memoizesReturns
React.memoComponent outputSame JSX if props unchanged
useCallbackFunction referenceSame function if deps unchanged
useMemoComputed valueCached value if deps unchanged
js
// React.memo — skip re-render if props shallow-equal const Child = React.memo(({ count }) => <p>{count}</p>); // useCallback — stable function reference const handleClick = useCallback(() => { ... }, [deps]); // useMemo — expensive calculation const sorted = useMemo(() => data.sort(compareFn), [data]);

2️⃣ When to Actually Use Them

Use memo/useCallback/useMemo when:

  • Child is in a React.memo wrapper and you pass functions/objects as props
  • Computation is genuinely expensive (large sort, filter, etc.)
  • Stable reference is required (dependency of useEffect)

Don't use when:

  • Component renders quickly anyway (adds overhead)
  • Props change on every render (memo comparison is wasted)
  • Premature optimization (profile first!)

Rule: Optimize after you measure, not before.

3️⃣ Why Shallow Comparison?

React uses shallow (reference) equality:

js
// Every render creates new reference — memo fails <Child onClick={() => doThing()} data={{value: 1}} /> // Stable references — memo works const onClick = useCallback(() => doThing(), []); const data = useMemo(() => ({value: 1}), []); <Child onClick={onClick} data={data} />

Deep comparison would be more expensive than the re-render itself.

Was this helpful?

Test your Knowledge

2 questions to cement what you just learned.