Onjsdev

Share


React useMemo Hook Explanation With Example


By onjsdev

Dec 9th, 2023

The useMemo hook is a method in React that allows you to improve your app's performance by memoizing values and recalculating them only when one of their dependencies changes.

In this guide, we will talk about useMemo hook's usage and comparison with the combination of the useEffect and useState hook by creating a simple project. Before we dive into the subject let's take a look our project overview.

Overview

With this example, especially, we would like to point out the role of the useMemo hook in app's performance optimization and differences with the combination of the useState and useEffect Hooks. Let's get started creating an example of how to use the useMemo in our react app.

Explanation Of The useMemo Hook Example

Simply put, we have two state variables, count and message in our component. We want to change their values with the buttons and render their values in screen.

First: Example Without Using useMemo Hook

The problem is that, if we clicked the button to change the message, we also see that the calculate method is rerun unnecessarily which is bad for the app's performance. This is why we use the useMemo Hook.

import { useState } from "react";

function App() {
  const [count, setCount] = useState(1);
  const [message, setMessage] = useState("Hello");

 // Expensive Calculation
  function calculate() {
    console.log("calculate function run");
    let result = 0;
    for (let i = 0; i < count; i++) {
      result += i;
    }
    return result;
  }

  const result = calculate();

  return (
    <div className="App">
      {message} {result}
      <button onClick={() => setCount((prev) => ++prev)}>Increase</button>
      <button onClick={() => setMessage((prev) => `${prev}!`)}>
        Change Message
      </button>
    </div>
  );
}

export default App;

Console Record To Show Calculate Method Runs Unnecessarily

Second: Example With useMemo Hook

Now, we will create the same example with the useMemo Hook to see the result. The useMemo hook gets two parameters, a function returning a value and dependecy array. In our case, the calculate method only will run when count value changes.

import { useMemo, useState } from "react";

function App() {
  const [count, setCount] = useState(1);
  const [message, setMessage] = useState("Hello");

  function calculate() {
    console.log("calculate function run");
    let result = 0;
    for (let i = 0; i < count; i++) {
      result += i;
    }
    return result;
  }

  // const result = calculate();
  // If the count changes, recalculate the result
  const result = useMemo(() => calculate(), [count]);

  return (
    <div className="App">
      {message} {result}
      <button onClick={() => setCount((prev) => ++prev)}>Increase</button>
      <button onClick={() => setMessage((prev) => `${prev}!`)}>
        Change Message
      </button>
    </div>
  );
}

export default App;

Console Record To Show Only Message Changes

You can think of that this performance optimization can also be achieved with the combination of the useState and useEffect Hook. Let's see the comparison of them.

useMemo vs useState + useEffect

Here is the same app with the useState and useEffect hook.

import { useEffect, useMemo, useState } from "react";

function App() {
  const [count, setCount] = useState(1);
  const [message, setMessage] = useState("Hello");

  console.log("render");
  function calculate() {
    console.log("calculate function run");
    let result = 0;
    for (let i = 0; i < count; i++) {
      result += i;
    }
    return result;
  }

  const [result, setResult] = useState();

  useEffect(() => {
    setResult(calculate());
  }, [count]);

  return (
    <div className="App">
      {message} {result}
      <button onClick={() => setCount((prev) => ++prev)}>Increase</button>
      <button onClick={() => setMessage((prev) => `${prev}!`)}>
        Change Message
      </button>
    </div>
  );
}

export default App;

In this test scenario, we will also change the count variable because we want to point to that the useEffect hook will causes an extra render as specified below.

Change Count -> Run useEffect -> Change Result
--------------                  --------------
    Render                           Render

Should I Always Use useMemo

As the official react document said, "You may rely on useMemo as a performance optimization, not as a semantic guarantee" which means react doesn't guarantee that it memoizes values, and also memoizing is a cost for your app, so use useMemo when needed to improve the performance of the application.

Conclusion

Performance of any application is so important therefore you may want to use the useMemo hook in your react js application to prevent unnecessary expensive calculation when needed.

Thank you for reading.