[React] What is useMemo?

·

3 min read

[React] What is useMemo?

useMemo is a React Hook that lets you cache the result of a calculation between re-renders.


How to use useMemo?

useMemo(calculateValue, dependencies)

import { useMemo } from 'react';

function TodoList({ todos, tab }) {
  const visibleTodos = useMemo(
    () => filterTodos(todos, tab),
    [todos, tab]
  );
  // ...
}

Parameters

  • calculateValue: The function calculating the value that you want to cache. It should be pure, should take no arguments, and should return a value of any type. React will call your function during the initial render. On next renders, React will return the same value again if the dependencies have not changed since the last render. Otherwise, it will call calculateValue, return its result, and store it so it can be reused later.

  • dependencies: The list of all reactive values referenced inside of the calculateValue code. Reactive values include props, state, and all the variables and functions declared directly inside your component body.

Returns

On the initial render, useMemo returns the result of calling calculateValue with no arguments.


When to use useMemo?

// index.tsx - before
import { useState } from 'react';
import { initialItems } from './utils';

interface DemoProps {}

function Demo({}: DemoProps) {
    const [count, setCount] = useState(0);
    const [items] = useState(initialItems);

    const selectedItem = items.find((item) => item.isSelected);

    return (
        <div>
            <h1>Count: {count}</h1>
            <h1>Selected Item: {selectedItem?.id}</h1>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );

export default Demo;
// utils.tsx
export const initialItems = new Array(29_999_999).fill(0).map((_, i) => {
    return {
        id: i,
        isSelected: i === 29_999_998,
    };
});

In this case, every time you click the Increment button, React updates the state of the count value which means you have to trigger a re-render of the entire component. And when React calculates the selectedItem, It has to do very expensive operation because it has to go through 29 million items to find the one that is selected. So if you keep pressing the button quickly, there will be a huge delay.

Since the items will continue to be the same value, there's no need to recompute selectedItem again except the first time. So if items are the same, we can just return the previous value in the next render.

// index.tsx - after
import { useMemo, useState } from 'react'; // useMemo added
import { initialItems } from './utils';

interface DemoProps {}

function Demo({}: DemoProps) {
    const [count, setCount] = useState(0);
    const [items] = useState(initialItems);

    // More efficient!
    const selectedItem = useMemo(
        () => items.find((item) => item.isSelected),
        [items],
    );

    return (
        <div>
            <h1>Count: {count}</h1>
            <h1>Selected Item: {selectedItem?.id}</h1>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );

export default Demo;

Using useMemo when you calculate the selectedItem can reduce unnecessary calculations when re-rendering and allows application to operate more efficiently.


Reference