useMemo vs useCallback: 3 React Optimization Tactics Senior Developers Use

Performance optimization in React is often seen as a minefield—where many developers get stuck making the wrong calls. Sprinkling useMemo and useCallback everywhere in hopes of speeding things up can backfire, forcing the CPU to do extra dependency comparisons for no reason. This article shows you how to use these two hooks like a pro.

useMemouseCallbackbí thuậttối ưu hiệu năngReactmemoization
Cover image: useMemo vs useCallback: 3 React Optimization Tactics Senior Developers Use
Avatar of Trung Vũ Hoàng

Trung Vũ Hoàng

Author

28/3/20264 min read

1. Understand the True Nature of Memoization

Everything in React has a trade-off. On every Component re-render, all variables and functions inside are created from scratch again. Memoization caches computed results or function definitions — if the inputs (dependencies) don’t change, React returns the cached version instead of recomputing.

However, caching also costs RAM and CPU to compare the dependency array on each render. So the number-one rule for a Senior Developer is: "Don’t optimize until you see clear, visible jank."

2. useMemo: Protect Expensive Computations

useMemo memorizes the return value of a computation. This hook truly shines when you’re processing large datasets — for example, filtering or sorting a list of 10,000 items every time the user interacts.

Without useMemo, the filter function will run again whenever the parent Component re-renders for any reason — even when the inputs haven’t changed. Wrapping this logic with useMemo ensures the computation only runs when it really needs to, keeping the frame rate steady at 60 fps.

const sortedList = useMemo(\n  () => heavySortAlgorithm(rawData),\n  [rawData]\n);

3. useCallback: Stabilize Function References

useCallback memorizes the function itself you pass in — not its return value. Why does this matter? Because in JavaScript, functions are objects. On every Component render, functions declared inside are created as new objects in memory, even if their logic hasn’t changed.

When you pass such a function as props to a child Component wrapped with React.memo, React will see a new function reference and trigger unnecessary re-renders. useCallback exists to prevent this — keeping the function reference stable across renders so React.memo can do its job.

4. The Easiest Way to Remember the Difference

  • useMemo memorizes a value — numbers, strings, a filtered array, complex objects.

  • useCallback memorizes a function — to be called later when needed.

The optimization goals differ:

  • useMemo → reduces CPU load (skips heavy computations).

  • useCallback → optimizes memory and re-renders (stabilizes function references for child Components).

A little-known detail: useCallback(fn, deps) is essentially shorthand for useMemo(() => fn, deps).

5. Real-World Lessons: When Not to Use Them?

Wrapping everything in memoization hooks is a common mistake among mid-level developers. Every time you use one, you’re asking React to perform an extra shallow comparison on the dependency array after each render.

If the function’s internal logic is trivial, or the function isn’t passed to any important child Component, using the hook can make the app slower. In practice, creating a new function in JavaScript is extremely fast — sometimes even faster than React comparing a complex dependency array.

Tactic 1: Measure First, Optimize Later

Use React DevTools Profiler to pinpoint exactly which Component is taking the most render time. Only after you’ve identified the real bottleneck should you apply memoization. This is the foundation of every sound optimization decision.

Tactic 2: Try Refactoring Components First

Before adding hooks, consider splitting a large Component into smaller Components (Composition Pattern). Many unnecessary re-render issues can be completely solved by designing the Component structure correctly — without any hooks at all.

Tactic 3: Lock Down the Dependency Array

If you’ve decided to use useMemo or useCallback, declare the dependency array fully and accurately. Missing a variable will create a Stale Closure — the function reads old data while you think it’s using the new data. This is one of the most silent and hardest-to-find bugs in React.

Conclusion

useMemo and useCallback are powerful tools — when used at the right time. Keep your code clean and natural first. Use the Profiler to measure. And only optimize when there’s real evidence, not gut feel.

Found this article helpful?

Contact us for a free consultation about our services

Contact us

Bài viết liên quan