React’s useMemo hook is often misunderstood. This is my attempt to explain its usage with a simple example.

Here is the code that we are going to start off with,

import { useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  const slowFunction = (count) => {
    for (let i = 0; i < 10000; i++) {
      count += 1;
      for (let i = 0; i < 10000; i++) {
        count += 1;
      }
      for (let i = 0; i < 10000; i++) {
        count += 1;
      }
    }
    console.log(`new count calculated: ${count}`);
    return count;
  };

  const valueFromSlowFunction = slowFunction(count);

  return (
    <div className="App">
      <button onClick={() => setCount(count + 1)}>Update Count</button>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <p>{valueFromSlowFunction}</p>
    </div>
  );
}

So at first glance, there seems to be a lot going on, but let me break it down for you.

We start with two simple React states:

  • A count state, that can be updated with a button click.
  • A text state that is bound to the input field.

Additionally, we have:

  • slowFunction is a function that is emulated to be slow.
  • valueFromSlowFunction is the variable that we would store this expensive function’s computed value in.

Now, using this code, I want you to try to change the value of the input field by typing in something. You’ll quickly notice that the typing feels quite laggy.

This is because every time you change the text state, a re-render is caused in the App component, which causes the expensive function to run and compute valueFromSlowFunction every single time you type in a character.

You would also notice that you get a new count calculated log statement in the console a bunch of times, which confirms that the slowFunction is being run every time the text state changes.

The way that we are going to solve this problem is by wrapping the computed value valueFromSlowFunction with the useMemo hook.

import { useState, useMemo } from "react";
...
const valueFromSlowFunction = useMemo(() => slowFunction(count), [count]);
...

How this works is, by passing in the count state in the dependency array of the useMemo hook, React memoizes the value of valueFromSlowFunction and doesn’t re-compute it across re-renders unless the count state in the dependency array changes.

Now, only when you update the count by pressing the “Update Count” button, the value will be computed again.