Хук оптимизации производительности useMemo в React
Первый хук для оптимизации
производительности, который мы рассмотрим
- это useMemo
.
Данный хук помогает кэшировать результаты ресурсоемких операций между моментами перерисовки экрана и соответственно может помочь избежать лишних объемных вычислений. Такое кэширование называют еще мемоизацией.
Посмотрим, как это работает. Давайте
создадим компонент с кнопкой и
заголовком h3
:
return (
<div>
<h3>Text</h3>
<button>click:</button>
</div>
);
А сейчас сделаем так, чтобы по клику
на заголовок его цвет менялся с оранжевого
на зеленый и обратно. Для начала
заведем стейт isGreen
:
const [isGreen, setIsGreen] = useState(false);
Добавим в атрибут style
заголовка
условие изменения цвета заголовку и
навесим обработчик клика:
<h3 onClick={() => setIsGreen(!isGreen)}
style={{ color: isGreen ? 'green' : 'orangered' }}
>Text</h3>
Пусть у нас также будет какое-то значение, которое будет увеличиваться при клике по нашей кнопочке на единицу. Заведем для него стейт:
const [num, setNum] = useState(0);
Добавим обработку клика по кнопке:
<button onClick={() => setNum(num + 1)}>
clicks
</button>
Пусть также у нас будет некая функция
square
, которая будет возвращать
квадрат значения num
. Результат
вызова функции мы будем записывать в
переменную result
:
const result = square(num);
function square(num) {
return num * num;
}
Выведем result
в тексте кнопки:
<button onClick={() => setNum(num + 1)}>
clicks: {result}
</button>
В результате у нас получилось следующее:
при клике на кнопку меняется значение
num
, которое затем возводится
в квадрат, а при клике на заголовок
меняется цвет заголовка.
У нас очень маленький компонент, все работает быстро, несмотря на то, что при клике по заголовку для смены его цвета весь компонент отрисовывается заново, соответственно происходят заново и вычисления, которые привязаны к кнопке, это даже при том, что мы к ней не прикасались. А теперь представьте, если бы наши вычисления были объемными и все пересчитывалось бы заново каждый раз.
Давайте, немного утяжелим нашу функцию, теперь она будет думать немного дольше. Таким образом мы сымитируем долгие вычисления:
function square(num) {
let startTime = performance.now();
while (performance.now() - startTime < 500) {
// Just do nothing ...
}
return num * num;
}
Понажимайте теперь на заголовок. Получается,
что теперь из-за долгой работы функции
square
(а кнопку-то мы не трогаем)
мы целую вечность должны ждать, чтобы у
заголовка поменялся цвет!
Здесь к нам на помощь и придет хук
useMemo
. Для этого, нам нужно первым
параметром передать функцию, вычисляющую
значение, которое мы хотим кэшировать,
данная функция должна быть чистой и не
принимать никаких параметров. А вторым
параметром - зависимости в квадратных
скобках, другими словами, все реактивные
значения, которые участвуют в коде
функции. Таким образом, в result
мы теперь впишем такую конструкцию:
const result = useMemo(() => square(num), [num]);
Снова понажимаем на заголовок. Теперь,
если мы не трогаем кнопку с вычислениями
и не меняем таким образом значение стейта
num
, то ничего не пересчитывается,
и React отображает кэшированное значение
в кнопке, поэтому наш заголовок
быстренько меняет свой цвет.
Создайте компонент App
, разместите
в нем абзац. Заведите стейт text
с начальным значением 'react'
,
пусть значение стейта отображается
в качестве текста абзаца. Пусть по клику
на абзац, ему в конец текста добавляется
восклицательный знак.
Заведите еще один стейт num
, с
начальным значением 0
. Разместите в
App
еще один абзац. Сделайте так,
чтобы при клике по нему num
увеличивалась на 1
.
А теперь добавьте в App
функцию
triple
, которая в качестве
параметра принимает num
и
возвращает его утроенное значение.
Положите результат вызова функции
в переменную result
. Отобразите
result
в качестве текста второго
абзаца. Покликайте по очереди на абзацы,
отметьте, как медленно добавляются
восклицательные знаки.
Исправьте ситуацию, обернув медленную
функцию triple
в useMemo
.