Cansu Arı Logo
Blog
What is it?

useCallback & useMemo: Do They *Really* Improve Performance?

useCallback and useMemo are touted for performance in React—but are they always necessary?

  • #React
  • #Performance

Skip to content

Should you add them to every render?

When it comes to React performance, two hooks jump to mind: useCallback and useMemo.
Many devs assume they belong everywhere. In reality, these hooks can sometimes do more harm than good.

Let’s clarify what they do, when to use them, and common misconceptions.


What is useCallback?

useCallback keeps a function’s reference stable across renders. Since functions are recreated on each render, child components may re-render unnecessarily.
const handleClick = useCallback(() => {
console.log('Clicked!')
}, [])
Now the function reference stays the same, reducing needless child renders.

When to use it

  • You pass a function as a prop to a child.
  • That child is optimized with React.memo().
  • Large lists or frequently re-rendering trees.

When to skip it

  • The function is used only in the same component.
  • Render frequency is low.
  • There’s no measured performance issue.
💡 TL;DR: useCallback is for reference stability, not a magic perf switch.

What is useMemo?

useMemo caches a computed value until its dependencies change. It prevents re-running expensive calculations on every render.
const sortedList = useMemo(() => {
return items.sort((a, b) => a.value - b.value)
}, [items])
As long as items is unchanged, the sort won’t rerun.

When to use it

  • Heavy computations (tables, filters).
  • Derived state (totals, aggregates).
  • When render includes costly calculations.

When to skip it

  • Trivial math/logic.
  • Cheap components.
  • When object/array identity isn’t important.
💡 TL;DR: useMemo trades memory for CPU. Use it when the trade is worth it.

useCallback vs useMemo

AspectuseCallbackuseMemo
What it cachesFunction referenceComputed value
Recomputes whenDependencies changeDependencies change
PurposeReference stabilityComputation cache
ReturnsFunctionValue
Rule: functions → useCallback, values → useMemo.

Real-world example

function ProductList({ products, onSelect }) {
const filtered = useMemo(() => products.filter(p => p.inStock), [products])
const handleClick = useCallback((id) => onSelect(id), [onSelect])

return (
<ul>
{filtered.map(p => (
<li key={p.id} onClick={() => handleClick(p.id)}>
{p.name}
</li>
))}
</ul>
)
}
  • useMemo caches the filtered list.
  • useCallback stabilizes the click handler reference.
Result: fewer renders, steadier performance. ✅

Misuse example

const doubled = useMemo(() => value * 2, [value])
This is unnecessaryvalue * 2 is cheap. useMemo adds memory and GC overhead; it can backfire.

💡 Remember: useMemo doesn’t always help; measure before adding.


With React.memo

React.memo prevents a child from re-rendering if its props are equal. But if function props change identity on every render, memo won’t help—this is where useCallback matters.
const Child = React.memo(({ onClick }) => {
console.log('Child render!')
return <button onClick={onClick}>Click</button>
})

function Parent() {
const handleClick = useCallback(() => console.log('Clicked!'), [])
return <Child onClick={handleClick} />
}
Now Child won’t re-render on every Parent render.

Deep computations with useMemo

useMemo is great for expensive math too:
const fibonacci = useMemo(() => calcFibonacci(40), [])
But if dependencies change every render, the cache won’t help. 😊

💡 Pro tip: No optimization without profiling. Add useMemo only where it moves the needle.


Measuring with DevTools

Use the React DevTools Profiler to measure render times. Only after identifying slow components should you apply useMemo/useCallback.

Steps

  1. Open Profiler.
  2. Interact (e.g., type in an input).
  3. Inspect render times.
  4. Add memo/useCallback and compare.
💡 Tip: Unnecessary optimization = unnecessary complexity.

Summary table

GoalHookWatch out
Stabilize function prop identityuseCallbackOnly if passed to children
Cache expensive derived valuesuseMemoOnly if it’s truly costly
Reduce child re-rendersReact.memoFunction props must be stable

Conclusion

useCallback and useMemo are micro-optimization tools, not cure-alls. Used correctly, they help; used blindly, they add noise.

In short:

  • useCallback → preserves function identity.
  • useMemo → caches computed results.
  • React.memo → skips re-renders when props don’t change.

All tags
  • React
  • Performance