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.

Trung Vũ Hoàng
Author
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.
Bài viết liên quan

Closures in JavaScript: Understand Them Thoroughly to Code Like a Pro
Closures—also known as "closed functions"—are one of the most powerful yet confusing concepts in JavaScript. Mastering closures not only helps you ace Senior-level interviews, but also changes how you architect your entire codebase: cleaner, safer, and less buggy. Many people confuse Scope and Closure, but they’re closely related and complementary. Let’s start from the foundations.

useEffect vs useMemo: 5 Key Differences You Need to Understand
Confusing useEffect and useMemo is one of the most common sources of performance issues in React apps. Think of useMemo as a calculator that remembers results, and useEffect as a switchboard operator waiting for external signals before acting.

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.