If you are not already familiar with the concept of hooks, be sure to check this article, as it provides a very good, in-depth overview of the concept of hooks, as well as some examples of them.

Introduction

The useMemo hook is used to return a cached value in order to save any re-computation overhead. It works similarly to the useCallback hook; you can read more about it here.

The useMemo hook is used to prevent a component from re-rendering unless its props have changed, meaning that we are now allowed to isolate resource-intensive computed values so that they won’t automatically run on every component render.

It would be better to showcase a scenario where it would be beneficial to use the hook so we can get a better understanding of the steps we’ve taken to reach an issue, and then explain the thought process behind using the useMemo hook.

Project Overview

We’ll start by scaffolding a brand-new React project. First, we’ll create a new project directory, after which we’ll initialize a new project using the terminal.

You can use either npm, npx, or yarn for this process. The command you would be running is:

  • npm: npm init react-app app-name
  • npx: npx create-react-app app-name
  • yarn: yarn create react-app app-name

Now that we’ve got everything set up, let’s get right to the fun part.

Project Progression

Since this is a small project we’ll put all of the code inside the App.js file under the root src directory, which will look something like this:

import { useState } from "react";
import "./App.css";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const calculation = expensiveCalculation(count);

  const increment = () => {
    setCount((c) => c + 1);
  };

  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <div className="App">
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => {
          return <p key={index}>{todo}</p>;
        })}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
        <h2>Expensive Calculation</h2>
        {calculation}
      </div>
    </div>
  );
};

const expensiveCalculation = (num) => {
  console.log("Calculating...");

  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }

  return num;
};

export default App;

The application from above is rather straightforward; we have a list of todos, a counter element, and finally, a function that once called, triggers some expensive calculations.

You can notice that the function is called each time the component re-renders.

So, what’s the issue?

When adding a new todo you will notice that there is a slight delay before anything happens. That is not expected, as both visually and functionality-wise they are unrelated.

Add todo delay

The root cause of the issue

The delay is caused by the expensive computation that is being triggered by each re-render of the App component. The re-renders of the App component are caused by its changes in state.

Solution

This is a perfect scenario for the usage of the useMemo hook, as it has been conceived to help us improve performance when dealing with expensive computations such as function calls.

By wrapping our expensiveCalculation function call within the useMemo hook, we will ensure that the result of this function call will only be recomputed when the values from the dependency array that the hook takes as a secondary argument change, otherwise it will be cached and not be influenced by external state changes or component re-renders.

With useMemo, our expensiveCalculation function will rather be used like this:

const calculation = useMemo(() => expensiveCalculation(count), [count]);

By passing the count variable to the useMemo‘s hook dependency array we let React know that unless the value of count variable changes, we’ll want to change the result of the expensiveCalculation function call.

If you were to now try reloading your browser tab and tried adding a new todo, you would be able to notice that it no longer lags behind:

Cached expensive computation with the use of the useMemo hook

That’ll only happen when updating the value of the count state variable, which is expected.

You can learn more about the memo HoC here. The functionality is similar to the useMemo hook, the difference being the syntax. You can check a realistic use-case in this article.

Summary

I hope you have enjoyed reading this article and that you’ve got a better understanding of what the useMemo hook is, what it does, and also when you should be using it.

Feel free to leave a comment below in case you have any questions, inquiries, or feedback to offer on this article.

See you on the next one. Cheers!

👋 Hey, I'm Vlad Mihet
I'm Vlad Mihet, a blogger & Full-Stack Engineer who loves teaching others and helping small businesses develop and improve their technical solutions & digital presence.

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.