Когда стоит использовать useMemo в React?
@truefrontenderЧасто ли вы прибегаете к использованию useMemo? Давайте рассмотрим, когда его применение действительно оправдано.
Цель и проблема, которую решает useMemo
При работе с функциональными компонентами в React весь код внутри тела функции выполняется при каждом обновлении компонента. Это означает, что тяжелые вычисления, находящиеся внутри компонента, будут пересчитываться при каждом его рендере. Эти операции могут привести к замедлению интерфейса приложения.
Чтобы справиться с этой проблемой, React предоставляет хук useMemo. Его главная задача — кэшировать результаты выполнения его первого аргумента(функции) между рендерами компонента. Это позволяет избежать повторных и ресурсоемких вычислений при обновлении компонента. Также в случае с ссылочными типами данных useMemo сохраняет ссылку на результат до тех пор, пока не произойдет необходимость его обновления.
Принцип работы useMemo
useMemo принимает функцию в качестве первого аргумента и массив зависимостей вторым. При первом рендере компонента он вызывает переданную функцию и кэширует её результат. В последующих обновлениях компонента, если зависимости не изменились, useMemo возвращает закэшированное значение, минуя повторные вычисления.
Однако, если при повторном рендере зависимости изменятся, useMemo повторно вызывает функцию и кэширует её новый результат.
Важно запомнить, что функция, передаваемая в хук useMemo, должна быть чистой. Про чистые функции можете прочитать в этом посте(тык).Также важно вызывать useMemo только на верхнем уровне компонента или кастомного хука и нельзя использовать внутри условий или циклов.
Примеры использования

На первый рендер вызовется функция из первого аргумента и сохранит ее результат. При повторных рендерах useMemo использует закэшированное значение, минуя повторные вычисления до тех пор, пока value не изменится.

В текущей реализации переменная memoizedResult всегда будет хранить значение, полученное во время первого рендера компонента. Даже если значение переменной value изменится, повторные вычисления не будут запускаться, поскольку мы передали пустой массив зависимостей вторым аргументом.

В данном примере у нас есть мемоизированный компонент, который перерисовывается при изменении его пропсов. Он принимает items в качестве массива. Если ссылка на items меняется, компонент перерисовывается. Без мемоизации calcFunction каждый раз возвращает новый массив, нарушая мемоизацию MemoizedComponent из-за изменения ссылки.
Решение: чтобы сохранить ссылку на результат и избежать ненужных обновлений нужно мемоизировать calcFunction и MemoizedComponent как в нашем примере выше.
Когда использовать useMemo?
- Мемоизация тяжелых вычислений: Если ваша компонентная логика включает в себя сложные вычисления, которые необходимо оптимизировать,
useMemoможет существенно снизить нагрузку путем кэширования результатов. - Мемоизация ссылочных типов данных: При передаче ссылочных типов данных (например, объектов, массивов) в мемоизированные компоненты или другие хуки в качестве зависимостей, использование
useMemoпозволяет сохранить ссылку на эти данные.
Также хочу отметить, что не следует всегда и всё оборачивать в useMemo. Этот хук не является бесплатным и в некоторых случаях может быть намного затратнее. Если кратко, то при каждом вызове useMemo создается новая функция и массив её зависимостей + дополнительные операции внутри хука. При повторном рендере в useMemo сравниваются зависимости и если они изменились, то создается новая функция и новый массив зависимостей.
Итого
useMemo в React предоставляет инструмент для оптимизации вычислений в функциональных компонентах. Он кэширует результаты выполнения функций между рендерами, помогая избежать лишних вычислений.
Используйте useMemo для:
- Мемоизации тяжелых вычислений.
- Сохранения ссылок на ссылочные типы данных, передаваемые в мемоизированные компоненты или другие хуки в качестве зависимостей.
Больше интересного в канале True Frontender