DEV Community

Jenish Dabhi
Jenish Dabhi

Posted on

Understanding useCallback and useMemo in React with Easy Examples

React's hooks have become an essential part of modern React development, offering functionality that was once achieved through class components. Among the most widely used hooks are useCallback and useMemo. These hooks help optimize your application’s performance by preventing unnecessary re-renders. In this blog post, we'll dive into what useCallback and useMemo are, when and why to use them, and illustrate both with practical examples.

What is useCallback?
useCallback is a hook that returns a memoized version of a function. It is used to prevent the recreation of the function on every render unless its dependencies change. This is particularly useful when passing functions as props to child components, preventing unnecessary re-renders of those child components.

Example of useCallback
Let’s say we have a parent component that passes a function to a child component. Without useCallback, the function would be re-created on every render of the parent, which could lead to unnecessary re-renders of the child component. Here's a simple example:

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

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

  const incrementCount = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []); // Empty dependency array ensures the function is only created once

  return (
    <div>
      <h1>Parent Component</h1>
      <p>Count: {count}</p>
      <ChildComponent incrementCount={incrementCount} />
    </div>
  );
}

function ChildComponent({ incrementCount }) {
  console.log("Child rendered");
  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
}

export default ParentComponent;

Enter fullscreen mode Exit fullscreen mode

In this example:

  • incrementCount is memoized using useCallback.

  • The ChildComponent receives the memoized function as a prop, and it won't re-render unless the incrementCount function changes, which, due to the empty dependency array [], won't happen unless the parent re-renders for a different reason.

  • By using useCallback, we prevent unnecessary re-renders of the ChildComponent.

What is useMemo?
useMemo is a hook that returns a memoized value, meaning it will only recalculate the value when one of its dependencies has changed. This can be useful when performing expensive calculations that don’t need to be recalculated on every render.

Example of useMemo
Let's say we have a component that computes a value based on user input, but this computation is expensive. Instead of recalculating the value every time the component re-renders, we can use useMemo to only recalculate when the input value changes.

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

function ExpensiveComputation() {
  const [number, setNumber] = useState(0);
  const [input, setInput] = useState("");

  // Memoize the expensive calculation
  const factorial = useMemo(() => {
    const calculateFactorial = (n) => {
      if (n === 0 || n === 1) return 1;
      return n * calculateFactorial(n - 1);
    };
    return calculateFactorial(number);
  }, [number]); // Only recompute factorial if `number` changes

  return (
    <div>
      <h1>Expensive Computation</h1>
      <p>Factorial of {number}: {factorial}</p>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(parseInt(e.target.value))}
      />
      <input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
      />
    </div>
  );
}

export default ExpensiveComputation;

Enter fullscreen mode Exit fullscreen mode
  • The factorial calculation is wrapped in useMemo, meaning it will only be recomputed when the number state changes.

  • Changing the input field does not trigger the recomputation of factorial, making the component more efficient.

When to Use useCallback and useMemo

Use useCallback when:

  • Passing a function as a prop to a child component, and the function does not need to be re-created on every render.

  • You are experiencing unnecessary re-renders of child components due to function props.

Use useMemo when:

  • You have an expensive calculation that does not need to run on every render.

  • The computed value is dependent on specific props or state, and you want to prevent unnecessary recalculations.

Conclusion
Both useCallback and useMemo are powerful hooks in React that help optimize the performance of your applications. By memoizing functions and values, you can prevent unnecessary re-renders and recalculations, leading to a smoother and more efficient user experience.

However, it's important to note that these hooks should be used sparingly. Overuse can lead to unnecessary complexity, and sometimes React’s built-in optimizations are enough. Always profile your app before optimizing, and use these hooks when performance bottlenecks are evident.

Hope this helps you understand when and how to use useCallback and useMemo in your React apps!

Top comments (0)