Народ, всем привет. Сегодня поговорим про React, а точнее, про один из его хуков. Сам по себе это Фреймворк (хотя это даже не он, но демагогию разводить не будем) предлагает множество инструментов для управления тем же состоянием или оптимизации производительности. И так, одним из таких инструментов является хук useMemo. Он не всем понятен, применяют его не многие, новички о нем часто даже и не знают. Поэтому, давайте сегодня мы разберём, что такое useMemo, как он работает, в каких случаях его стоит использовать и когда от него лучше отказаться.
Что такое useMemo?
Для начала это хук, который позволяет мемоизировать (кешировать) вычисления в функциональных компонентах React. Это значит, что если входные зависимости не изменились, React вернёт ранее вычисленное значение, а не будет выполнять вычисление заново.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Тут, computeExpensiveValue — функция, выполняющая тяжёлые вычисления, а [a, b] — массив зависимостей. Если они не изменились, то useMemo вернёт сохранённый результат.
Если все равно не понятно, то давайте более подробно разберем, как это все работает… Рассмотрим простой пример, который демонстрирует, как useMemo предотвращает повторное выполнение функции. Что происходит на картинке (номер 1):
- функция expensiveCalculation выполняет дорогостоящие вычисления (возведение числа в квадрат).
- useMemo предотвращает повторный вызов expensiveCalculation, если num не изменился.
- кнопка "Увеличить счётчик" не вызывает пересчёт квадрата, потому что useMemo сохраняет предыдущее значение.
useMemo также полезен при работе с массивами и объектами, поскольку в React они сравниваются по ссылке, а не по значению. Это может привести к ненужным ререндерам. Если разобрать пример номер два, то мы увидим:
- useMemo предотвращает повторное вычисление filteredList, если список list и фильтр filter не изменились.
- без `useMemo` функция `filter` вызывалась бы при каждом ререндере, даже если список не изменился.
Когда использовать `useMemo`?
useMemo — мощный инструмент для оптимизации функциональных компонентов в React. Однако применять его стоит осознанно, только в тех случаях, когда это действительно необходимо. Чрезмерное использование `useMemo` может привести к усложнению кода без реальной выгоды. Главное правило: оптимизируйте только там, где это действительно нужно!
1. Оптимизация сложных вычислений. Если в компоненте есть функция, которая выполняет дорогостоящие вычисления, `useMemo` поможет избежать их повторного выполнения без необходимости.
const computedValue = useMemo(() => veryExpensiveFunction(data), [data]);
2. Избежание ненужных ререндеров. Если передаёте вычисляемое значение в дочерний компонент, `useMemo` может предотвратить его пересоздание и снизить количество ререндеров.
const memoizedObject = useMemo(() => ({ key: value }), [value]);
3. Использование в связке с useCallback. useMemo часто используется совместно с useCallback, который мемоизирует функции.
Есть ли случаи, когда не стоит использовать useMemo? Да полно. Например, когда вычисления не являются ресурсоёмкими. Какой смысл, если вычисления занимают миллисекунды, и useMemo не принесёт пользы, и даже может ухудшить производительность.
const simpleValue = useMemo(() => x + y, [x, y]); // оно тут просто не нужно!
2. Когда зависимости часто меняются
Если зависимости useMemo часто обновляются, мемоизация не даёт выигрыша в производительности, так как расчёты выполняются заново при каждом изменении.
const changingValue = useMemo(() => compute(value), [value]);
// Если value меняется на каждом рендере, смысла в useMemo нет
3. Когда код остаётся читаемым без useMemo
Излишнее использование useMemo может ухудшить читаемость кода без реальной выгоды.
Пример без useMemo:
const computedValue = compute(a, b); // Просто и понятно
Пример с useMemo без необходимости:
const computedValue = useMemo(() => compute(a, b), [a, b]);