DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Mastering `useMemo` and `useCallback` in React: A Deep Dive

Mastering  raw `useMemo` endraw  and  raw `useCallback` endraw  in React: A Deep Dive<br>

Mastering useMemo and useCallback in React: A Deep Dive

In modern React development, performance and precision matter more than ever. Two powerful hooks, useMemo and useCallback, empower developers to optimize rendering behavior, avoid unnecessary recalculations, and manage referential integrity.

In this article, we will explore these two hooks through an advanced real-world example: simulating an expensive math operation in a component and preventing unnecessary renders. We'll cover their use cases, differences, similarities, and best practices to use them effectively.


What Are useMemo and useCallback?

useMemo

  • Purpose: Memoizes the result of a computation.
  • When to use: When an expensive calculation should be recomputed only when its dependencies change.
  • Returns: A memoized value.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Enter fullscreen mode Exit fullscreen mode

useCallback

  • Purpose: Memoizes the function reference itself.
  • When to use: When a function is passed to child components or included in dependencies and you want to avoid re-creating it on every render.
  • Returns: A memoized function.
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);
Enter fullscreen mode Exit fullscreen mode

Real-World Example: Fibonacci + Expensive Render Simulation

We'll use both hooks to:

  • Optimize a simulated heavy calculation (Fibonacci).
  • Avoid recreating functions using useCallback.

The Code

import React, { useState, useMemo, useCallback } from 'react';

const fibonacci = (n: number): number => {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

const ExpensiveCalculation = ({ number }: { number: number }) => {
  const result = useMemo(() => fibonacci(number), [number]);
  console.log('🔄 ExpensiveCalculation rendered');
  return <p>Fibonacci({number}) = {result}</p>;
};

const Counter = ({ onIncrement }: { onIncrement: () => void }) => {
  console.log('🔁 Counter rendered');
  return <button onClick={onIncrement}>+1</button>;
};

export const OptimizedComponent = () => {
  const [count, setCount] = useState(0);
  const [fibNumber, setFibNumber] = useState(20);

  const increment = useCallback(() => setCount((prev) => prev + 1), []);

  return (
    <div>
      <h2>useMemo & useCallback Demo</h2>
      <Counter onIncrement={increment} />
      <p>Clicked: {count}</p>

      <input
        type="number"
        value={fibNumber}
        onChange={(e) => setFibNumber(Number(e.target.value))}
      />

      <ExpensiveCalculation number={fibNumber} />
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Why This Works

useMemo Benefits

  • Without useMemo, fibonacci(number) would re-run on every render, even when unrelated state like count changes.
  • useMemo memoizes the result unless number changes.

useCallback Benefits

  • Without useCallback, onIncrement would get a new reference each time, triggering unnecessary re-renders in child components.
  • useCallback ensures Counter only re-renders when truly needed.

Differences Between useMemo and useCallback

Feature useMemo useCallback
Memoizes Return value of function Function itself
Use case Avoid recalculating values Avoid recreating function refs
Return type Any value A function
Helps with Expensive calculations Referential equality (e.g. props)

Best Practices

  • Use these hooks only when necessary. Over-optimization may lead to more complexity.
  • Ensure dependencies arrays are accurate and complete.
  • Prefer useMemo for derived values and useCallback when passing functions to children or in useEffect.

Bonus: Visualizing Re-renders

You can integrate why-did-you-render or React DevTools Profiler to visualize how memoization impacts rendering behavior.


Conclusion

React's useMemo and useCallback are powerful hooks that help fine-tune performance and reference stability. Understanding when and how to use them can significantly enhance your app's responsiveness and efficiency.

By combining these hooks, you can:

  • Prevent unnecessary re-renders
  • Speed up expensive calculations
  • Pass stable functions to child components

Mastering these hooks is a major step toward becoming a true React expert. 🔥


#react #typescript #frontend #performance #memoization #hooks #useMemo #useCallback

Top comments (0)