DEV Community

Mohamed Idris
Mohamed Idris

Posted on

The useMemo react hook: Optimizing Expensive Calculations with useMemo

In React, useMemo is a hook used to memoize a value, which means it remembers the result of a computation so it doesn’t have to be recalculated unless necessary. This is useful for optimizing performance, especially when you have expensive calculations that don’t change often.

How useMemo Works:

useMemo takes two arguments:

  1. A function that returns the value you want to memoize.
  2. A dependency array that tells React when to recalculate the value. If the values in this array haven't changed, React will return the memoized value without recalculating it.

Example: Without useMemo

In this example, every time the button is clicked, the slowFunction is executed, which is a performance issue because it's a long-running calculation.

import { useState, useCallback } from 'react';
import { data } from '../../../../data';
import List from './List';

const slowFunction = () => {
  let value = 0;
  for (let i = 0; i <= 1000000000; i++) {
    value += i;
  }
  return value;
};

const App = () => {
  const [people, setPeople] = useState(data);
  const [count, setCount] = useState(0);

  const value = slowFunction();
  console.log(value); // The slow function runs on each click

  const removePerson = useCallback(
    (id) => {
      const newPeople = people.filter((person) => person.id !== id);
      setPeople(newPeople);
    },
    [people]
  );

  return (
    <section>
      <button
        className="btn"
        onClick={() => setCount(count + 1)}
        style={{ marginBottom: '1rem' }}
      >
        count {count}
      </button>
      <List people={people} removePerson={removePerson} />
    </section>
  );
};
export default App;
Enter fullscreen mode Exit fullscreen mode

Issue: Every time the count changes, the slowFunction runs, even though the result doesn’t change. This can cause performance problems.

Before using useMemo


Example: With useMemo

We can use useMemo to ensure that the slowFunction only runs once, unless the dependencies change (in this case, there are no dependencies, so it runs only once on the initial render).

import { useState, useMemo } from 'react';
import { data } from '../../../../data';
import List from './List';

const slowFunction = () => {
  let value = 0;
  for (let i = 0; i <= 1000000000; i++) {
    value += i;
  }
  return value;
};

const App = () => {
  const [people, setPeople] = useState(data);
  const [count, setCount] = useState(0);

  const value = useMemo(() => slowFunction(), []);
  // OR const value = useMemo(slowFunction, []);
  console.log(value); // Now the slow function runs only once

  const removePerson = (id) => {
    const newPeople = people.filter((person) => person.id !== id);
    setPeople(newPeople);
  };

  return (
    <section>
      <button
        className="btn"
        onClick={() => setCount(count + 1)}
        style={{ marginBottom: '1rem' }}
      >
        count {count}
      </button>
      <List people={people} removePerson={removePerson} />
    </section>
  );
};
export default App;
Enter fullscreen mode Exit fullscreen mode

What Changed:

  • We wrapped the slowFunction call inside useMemo, which will only execute once, when the component first renders.
  • The slow function result is now memoized, so it doesn't need to be recalculated on every re-render, improving performance.

After using useMemo


Summary of useMemo

  • Purpose: To memoize expensive calculations and avoid unnecessary recomputations.
  • Arguments:
  1. The function that returns the value you want to memoize.
  2. The dependency array that controls when the memoized value should be recalculated.
    • Performance Boost: It prevents recalculating values on every render, especially when the dependencies haven’t changed.

Top comments (1)

Collapse
 
edriso profile image
Mohamed Idris

useCallback vs useMemo

  • useCallback is used to memoize a function, ensuring that the function reference remains the same between renders unless its dependencies change. It's useful when passing functions to child components to avoid unnecessary re-renders.

  • useMemo is used to memoize the result of a computation (the value returned by a function). It's useful when you want to avoid expensive recalculations unless specific dependencies change.

In short:

  • Use useCallback when you need to memoize a function.
  • Use useMemo when you need to memoize a computed value.