React UseMemo

React UseMemo

Что такое useMemo?

useMemo - это хук React, который позволяет кэшировать результат вычислений между рендерами.

Как правило, useMemo уменьшает объем работы, которую необходимо выполнить при данном рендере. useMemo может мемоизировать функцию и ее результат, что означает, что если входы функции не изменяются, React вернет мемоизированное значение вместо повторного вычисления, что потенциально ускорит процесс рендеринга.

Простое объяснение

Допустим, у нас есть очень медленная функция, которая занимает огромное количество времени на вычисление в процессе рендеринга:

// a really slow function...
const slowFunction = (num) => {
  for (let i = 0; i < 1000000000; i++) { }
  return num * 2;
}

И нам нужен результат этой slowFunction для рендеринга веб-страницы, например, переменная complexResult:

const complexResult = slowFunction(input);
<p> { complexResult } </p>

В этом случае вызов slowFunction в каждом рендере значительно замедлит работу вашего приложения. Вот здесь и пригодится useMemo.

Мы можем обернуть slowFunction внутри useMemo и предоставить массив зависимостей. Массив зависимостей используется для определения того, нужно ли пересчитывать мемоизированное значение. Если какая-либо из зависимостей изменится, useMemo пересчитает мемоизированное значение, или просто будет использовать предыдущее ”мемоизированное” значение.

Простая метафора может быть такой:

  • если я решаю головоломку в первый раз, мне нужно потратить время на прохождение всех шагов, пока я не решу ее и не дам ответ.
  • Если вы попросите меня решить ту же головоломку во второй раз, мне не придется проходить все шаги еще раз. Вместо этого я просто дам вам ответ прямо, потому что он уже есть в моем мозгу.
  • Если вы попросите меня решить другую головоломку, мне все равно придется потратить время на прохождение всех шагов.

Вот:

  • процесс решения головоломки — это slowFunction
  • ответ - complexResult
  • проблема головоломки — зависимость.

Как использовать UseMemo?

Прототип приведен ниже:

const cachedValue = useMemo(calculateValue, dependencies);

где

  • calculateValue: Функция, вычисляющая значение, которое вы хотите кэшировать. (обычно это медленные функции)
  • зависимости: Список всех реактивных значений, на которые ссылается код calculateValue.
  • cachedValue: тот же результат вызова calculateValue.

Вернемся к нашему примеру, ранее мы имели:

const complexResult = slowFunction(input);

А с помощью UseMemo эту строку можно изменить на:

const complexResult = useMemo(() => {
  return slowFunction(input)
}, [input])

В приведенном выше примере complexResult будет пересчитан только в том случае, если изменится зависимость ввода. Если входные данные останутся прежними, React вернет ранее мемоизированное значение, что избавит нас от необходимости снова и снова вызывать slowFunction.

Полный пример

Если вы все еще считаете эту концепцию абстрактной или вам просто нужно немного контекста для размышлений. Ниже приведен немного более сложный пример.

Без useMemo

import { useState } from "react";

const slowFunction = (num) => {
  console.log("running slow double calculation...");
  for (let i = 0; i < 1000000000; i++) {}
  return num * 2;
};

const Demo = () => {
  const [number, setNumber] = useState(0);
  const [color, setColor] = useState("black");

  const doubledNumber = slowFunction(number);

  return (
    <div>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <button onClick={() => setColor(color === "black" ? "green" : "black")}>
        Change Color!
      </button>
      <p style={{ color: color }}>{doubledNumber}</p>
    </div>
  );
};

export default Demo;

Что произошло после нажатия кнопки изменения цвета?

  • setColor вызвал повторный рендеринг
  • Пересчет удвоенного числа занимает много времени
  • Приводит к медленному рендерингу удвоенного числа

С помощью UseMemo

import { useState, useMemo } from "react";

const slowFunction = (num) => {
  console.log("running slow double calculation...");
  for (let i = 0; i < 1000000000; i++) {}
  return num * 2;
};

const Demo = () => {
  const [number, setNumber] = useState(0);
  const [color, setColor] = useState("black");

  const doubledNumber = useMemo(() => {
    return slowFunction(number);
  }, [number]);

  return (
    <div>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <button onClick={() => setColor(color === "black" ? "green" : "black")}>
        Change Color!
      </button>
      <p style={{ color: color }}>{doubledNumber}</p>
    </div>
  );
};

export default Demo;

Благодаря UseMemo нам больше не придется долго ждать установки цвета после изменения номера.

Напоминание: Не используйте UseMemo повсеместно!

Причины следующие:

  • Чрезмерное использование useMemo может снизить производительность и внести ненужные накладные расходы.
  • Мемоизация наиболее эффективна для дорогих вычислений, которые дают одинаковый результат при одинаковых входных данных.
  • Чрезмерное использование useMemo может сделать ваш код более сложным для чтения и сопровождения.

Ссылка

useMemo. React. (n.d.). Получено 25 апреля 2023 года с https://react.dev/reference/react/useMemo.