DEV Community

Jaydeep Pipaliya
Jaydeep Pipaliya

Posted on

React : useCallback vs useMemo

useCallback vs useMemo

These are both optimization hooks in React, but they serve slightly different purposes.

Let's break it down:

1. Purpose:

  • useCallback is used to memoize functions.
  • useMemo is used to memoize values.

2. What they return:

  • useCallback returns a memoized callback function.
  • useMemo returns a memoized value of any type.

3. Use cases:

  • useCallback is typically used when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
  • useMemo is used to avoid expensive calculations on every render.

4. Syntax:

   const memoizedCallback = useCallback(
     () => {
       doSomething(a, b);
     },
     [a, b],
   );

   const memoizedValue = useMemo(
     () => computeExpensiveValue(a, b),
     [a, b]
   );
Enter fullscreen mode Exit fullscreen mode

5. Performance implications:

  • useCallback can help prevent unnecessary re-renders of child components that receive the callback as a prop.
  • useMemo can help avoid expensive recalculations when the dependencies haven't changed.

Let's look at some examples to illustrate the differences:

Example using useCallback:

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

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

  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <ChildComponent onClick={handleClick} />
      <p>Count: {count}</p>
    </div>
  );
};

const ChildComponent = React.memo(({ onClick }) => {
  console.log('ChildComponent rendered');
  return <button onClick={onClick}>Increment</button>;
});
Enter fullscreen mode Exit fullscreen mode

In this example, useCallback is used to memoize the handleClick function. This is useful because ChildComponent is wrapped in React.memo, which means it will only re-render if its props change. By using useCallback, we ensure that handleClick maintains the same reference between renders (unless count changes), preventing unnecessary re-renders of ChildComponent.

Example using useMemo:

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

const ExpensiveComponent = ({ list }) => {
  const sortedList = useMemo(() => {
    console.log('Sorting list');
    return [...list].sort((a, b) => a - b);
  }, [list]);

  return (
    <div>
      <h2>Sorted List:</h2>
      {sortedList.map(item => <div key={item}>{item}</div>)}
    </div>
  );
};

const ParentComponent = () => {
  const [list] = useState([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]);
  const [count, setCount] = useState(0);

  return (
    <div>
      <ExpensiveComponent list={list} />
      <button onClick={() => setCount(count + 1)}>
        Clicked {count} times
      </button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

In this example, useMemo is used to memoize the sorted list. The expensive sorting operation will only be performed when the list prop changes, not on every render of ExpensiveComponent. This is particularly useful here because ParentComponent might re-render for reasons unrelated to the list (like when count changes), and we don't want to re-sort the list unnecessarily.

Key Takeaways:

  1. Use useCallback when you want to prevent unnecessary re-renders of child components that depend on function references.
  2. Use useMemo when you want to avoid expensive recalculations of values.
  3. Both hooks help with performance optimization, but they should be used judiciously. Overuse can lead to increased complexity without significant performance gains.
  4. The dependency array in both hooks is crucial. The memoized value/function will only update if one of the dependencies changes.

follow for more content like these!

Top comments (0)