Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 24, 20264 min read

React performance: When to use useMemo and useCallback

React performance depends on knowing when to memoize. Learn the mental model for using useMemo and useCallback effectively without falling into optimization traps.

ReactFrontendPerformanceJavaScriptWeb DevelopmentNext.jsTutorial

I remember sitting through an on-call rotation where a senior dev—who should have known better—wrapped every single function in useCallback and every object in useMemo. They thought they were building a "fast" app. Instead, they built a memory-hungry monster that was actually slower than the original implementation.

We've all been there, tempted to reach for useMemo or useCallback the moment a component feels a bit sluggish. But memoization isn't free. If you're struggling to understand the right time to reach for these hooks, you aren't alone. It’s a common hurdle when you’re moving from "making it work" to "making it scale."

The Real Cost of React Performance Optimization

Before we dive into the syntax, let’s talk about the cost. Memoization works by storing the result of a calculation or a function reference in memory. On subsequent renders, React compares the dependencies you provided to the previous ones. If they’re the same, it returns the cached version.

The catch? That comparison isn't free. You’re trading CPU cycles (for re-running code) for memory (to store the cached result) and extra logic (to compare dependencies). Sometimes, the cost of checking the dependencies is higher than the cost of just re-running the function.

I usually tell juniors to look at it this way:

  1. Is the calculation expensive? (e.g., filtering a list of 5,000 items).
  2. Is the dependency stable? (Does this value actually change often?).
  3. Is the identity of this function causing a downstream effect? (Is it a prop passed to a React.memo component?).

If the answer to all three is "no," you don't need memoization.

When to use useMemo

You should use useMemo when you have a function that performs a heavy computation. In a recent project, we had a data transformation utility that took around 15ms to run on every render. That doesn't sound like much, but when you have a list of 50 rows, you’re suddenly looking at a 750ms blocking time just for data processing.

JAVASCRIPT
const filteredData = useMemo(() => {
  return performExpensiveCalculation(rawData, filterCriteria);
}, [rawData, filterCriteria]);

That’s a classic win. The calculation only runs when rawData or filterCriteria changes. If the component re-renders because of a parent state change that doesn't affect these two variables, the calculation is skipped entirely.

Leveraging useCallback for Referential Equality

The useCallback hook is slightly different. It doesn't cache a value; it caches a function reference. This is crucial when you pass functions down as props to child components wrapped in React.memo.

If you don't use useCallback, the child component sees a "new" function on every render, even if the logic inside is identical. This triggers a re-render in the child, effectively breaking the optimization you were trying to achieve.

Here is where I see most people go wrong: they wrap every event handler in useCallback. Don't do that. Only use it when:

  • The child component is heavy or wrapped in React.memo.
  • The function is a dependency in a useEffect hook.

If the component is just a standard button or an input, the overhead of creating the function is smaller than the overhead of managing the useCallback dependency array.

Avoiding Premature Optimization

If you find yourself constantly guessing, stop. You need to verify your assumptions. I highly recommend spending time on React performance debugging: How to trace component re-renders before you start sprinkling memoization everywhere.

Often, the issue isn't a slow calculation—it's an unnecessary re-render caused by state being lifted too high or a missing key prop in a list. I’ve seen developers spend hours memoizing components only to realize their state management was the real bottleneck.

If you are dealing with massive data sets, you might also want to look into Progressive Hydration: Boosting Perceived Performance on Large Dashboards. Sometimes the solution isn't making the code faster, but changing when the code runs.

FAQ: Common Memoization Questions

Q: Should I wrap all my event handlers in useCallback? A: No. It adds complexity and memory overhead. Only do it if you are passing the function to a memoized child component that depends on prop stability to avoid re-renders.

Q: Does useMemo always make things faster? A: Definitely not. For simple calculations (like adding two numbers), the cost of the hook and the dependency comparison can be slower than the calculation itself.

Q: How do I know if my calculation is "expensive"? A: If you aren't sure, don't guess. Use the React DevTools Profiler. If a component isn't taking more than a few milliseconds to render, you likely don't need to optimize it.

Final Thoughts

The best advice I can give you is to treat memoization as a surgical tool, not a blunt instrument. Start by building your UI cleanly. If you notice jank or the Profiler shows a component re-rendering unnecessarily, investigate why.

I’m still surprised by how often I see devs reach for useMemo before they even measure the render time. Next time, try deleting your memoization hooks and see if the app actually gets slower. You might be surprised to find it makes zero difference—or that it actually feels snappier because you’ve removed the overhead of the dependency checks.

Back to Blog

Similar Posts

ReactNext.jsJune 24, 20264 min read

React reconciliation explained: How to optimize your DOM updates

React reconciliation is the engine behind your UI updates. Learn how DOM diffing works and how to minimize mutations to keep your React app fast.

Read more
ReactNext.js
June 24, 2026
3 min read

React form handling: Controlled vs. Uncontrolled Components

React form handling doesn't have to be complex. Learn the trade-offs between controlled and uncontrolled components to decide when to sync your UI state.

Read more
ReactNext.jsJune 22, 20264 min read

React derived state: Stop using useEffect for data calculations

React derived state is the key to faster components. Learn how to stop abusing useEffect for data transformations and simplify your React performance optimization.

Read more