DEV Community

codeek
codeek

Posted on

🚀useMemo vs useCallback Hooks in React for Performance Optimiztion: A Step-by-Step Guide with Practical Examples

useMemo vs useCallback in React: A Step-by-Step Guide with Practical Examples

React applications re-render whenever state or props change. While this behavior is essential, unnecessary re-renders and expensive calculations can negatively impact your application's performance.

React provides two optimization hooks to solve these problems:

  • ⚡ useMemo – Memoizes values
  • ⚡ useCallback – Memoizes functions

Although they seem similar, they solve different performance issues. In this guide, you'll learn when to use each hook and how to implement them correctly.


What is useMemo?

useMemo caches the result of an expensive calculation and only recalculates it when one of its dependencies changes.

Syntax

const memoizedValue = useMemo(() => {
  return expensiveCalculation(data);
}, [data]);
Enter fullscreen mode Exit fullscreen mode

Think of it as:

"Don't recalculate this value unless something important changes."


When Should You Use useMemo?

Use useMemo when:

  • Filtering large arrays
  • Sorting data
  • Complex mathematical calculations
  • Data transformations
  • Expensive computations

Avoid using it for simple calculations because memoization itself has a small overhead.


Step 1: Without useMemo

Imagine we have thousands of products.

function ProductList({ products, search }) {
  const filteredProducts = products.filter(product =>
    product.title.toLowerCase().includes(search.toLowerCase())
  );

  return (
    <>
      {filteredProducts.map(product => (
        <p key={product.id}>{product.title}</p>
      ))}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Every render runs:

products.filter(...)
Enter fullscreen mode Exit fullscreen mode

Even if products and search never changed.


Step 2: Optimize with useMemo

import { useMemo } from "react";

function ProductList({ products, search }) {
  const filteredProducts = useMemo(() => {
    return products.filter(product =>
      product.title.toLowerCase().includes(search.toLowerCase())
    );
  }, [products, search]);

  return (
    <>
      {filteredProducts.map(product => (
        <p key={product.id}>{product.title}</p>
      ))}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now React only recalculates the filtered products when:

  • products change
  • search changes

Otherwise it reuses the cached value.


What is useCallback?

Unlike useMemo, useCallback memoizes functions, not values.

Without it, every render creates a brand new function.

const handleClick = () => {
  console.log("Clicked");
};
Enter fullscreen mode Exit fullscreen mode

Every render creates a new function reference.


Why is This a Problem?

Consider this component:

const Child = React.memo(({ onClick }) => {
  console.log("Child Rendered");

  return (
    <button onClick={onClick}>
      Click Me
    </button>
  );
});
Enter fullscreen mode Exit fullscreen mode

Even though Child is wrapped with React.memo, it still re-renders because:

onClick !== previousOnClick
Enter fullscreen mode Exit fullscreen mode

The function reference changes every render.


Step 3: Without useCallback

function Parent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    console.log("Clicked");
  };

  return (
    <>
      <button onClick={() => setCount(count + 1)}>
        Count {count}
      </button>

      <Child onClick={handleClick} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Every time count changes:

  • Parent renders
  • handleClick is recreated
  • Child renders again

Step 4: Optimize with useCallback

import { useCallback } from "react";

function Parent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Clicked");
  }, []);

  return (
    <>
      <button onClick={() => setCount(count + 1)}>
        Count {count}
      </button>

      <Child onClick={handleClick} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now the function reference stays the same.

If the child component is memoized using React.memo, it won't unnecessarily re-render.


useMemo vs useCallback

useMemo useCallback
Memoizes values Memoizes functions
Prevents expensive recalculations Prevents unnecessary function recreation
Returns computed value Returns memoized function
Useful for filtering, sorting, calculations Useful when passing callbacks to child components

Which One Should You Use?

Use useMemo when:

  • Filtering arrays
  • Sorting data
  • Expensive calculations
  • Transforming API responses

Use useCallback when:

  • Passing callbacks to child components
  • Using React.memo
  • Preventing unnecessary child re-renders
  • Stable event handlers

Common Mistakes

❌ Using useMemo Everywhere

const value = useMemo(() => count + 1, [count]);
Enter fullscreen mode Exit fullscreen mode

This calculation is trivial and doesn't need memoization.


❌ Forgetting Dependencies

useMemo(() => calculate(products), []);
Enter fullscreen mode Exit fullscreen mode

Always include all required dependencies.


❌ Using useCallback Without React.memo

If child components aren't memoized, useCallback often provides little or no performance benefit.


Performance Tips

  • âś… Measure performance before optimizing.
  • âś… Use useMemo only for expensive computations.
  • âś… Use useCallback for stable function references.
  • âś… Combine React.memo with useCallback for the best results.
  • âś… Don't overuse memoization—simplicity is often better.

Conclusion

Both useMemo and useCallback are powerful optimization hooks, but they solve different problems.

  • useMemo caches computed values.
  • useCallback caches functions.

Understanding the difference helps you write faster, cleaner, and more efficient React applications.


🎥 Watch the Complete Video Tutorial

Want to see everything implemented step by step?

📺 Watch the full tutorial here:

https://www.youtube.com/watch?v=lIVngCxky38

In the video, you'll learn:

  • Complete implementation
  • Real-world examples
  • Performance optimization techniques
  • Common mistakes to avoid
  • Best practices for modern React applications

🚀 Learn React by Building a Complete Ecommerce Project

If you're serious about mastering React through real-world projects, check out our complete Ecommerce tutorial series.

You'll learn:

  • React Fundamentals
  • React Router
  • Context API
  • Authentication & Authorization
  • Shopping Cart
  • Product Filtering
  • Stripe Payment Integration
  • Firebase
  • Express.js Backend
  • Modern React Best Practices

🎥 Start the Ecommerce Playlist:

https://youtu.be/SdITjnl-zo8?si=IbA-E-Xe1ctJBEnY

Happy Coding! 🚀

Top comments (0)