Когда в React v16.8 были представлены хуки React, разработчики наконец получили возможность управлять состоянием в функциональных компонентах с помощью таких хуков, как useState
, useEffect
и другие. В этой статье мы рассмотрим ловушку React useMemo
и то, как с ее помощью можно писать более быстрый код React.
Чтобы понять, почему useMemo
вообще существует, сначала рассмотрим, как работает рендеринг.
Равенство функций и дорогостоящие операции
useMemo
по своей сути стремится решить две проблемы: равенство функций и дорогостоящие операции.
В течение жизненного цикла компонента React повторно отображает компонент при каждом обновлении. Это означает, что React перестроит все функции и переменные в компоненте React, что потенциально является очень дорогостоящей операцией для более сложных компонентов React.
По умолчанию объекты в Javascript уникальны. Например, давайте посмотрим на этот код:
Здесь у нас есть два объекта, x
и y
, которые имеют одинаковую структуру. Однако по сравнению с Javascript они не имеют одинаковой ценности!
Когда React проверяет наличие изменений в компоненте, из-за этой проблемы с равенством объектов он может без необходимости повторно отображать дерево компонентов из-за воспринимаемых изменений в объектах, когда на самом деле объект имеет точно такие же значения.
Здесь на помощь приходит техника, называемая мемоизацией.
Что такое мемоизация?
Мемоизация похожа на кеширование операции или значения. Например, допустим, у нас есть функция, которая вычисляет 1+1
и возвращает 2
. Если мы запомним эту функцию, в следующий раз, когда она будет использовать ее для вычисления 1+1
, она запомнит, что 1+1
равно 2
, без повторного запуска функции!
Это может быть невероятно мощным средством для ускорения сложных операций.
useMemo
Из официальной документации React useMemo
выглядит так:
const memoizedValue = React.useMemo(() => computeExpensiveValue(a, b), [a, b]);
Обратите внимание, что мы передаем функцию, в данном случае computeExpensiveValue
, и массив зависимостей [a, b]
. Зависимости аналогичны аргументам функции, они useMemo
следят за тем, должна ли она выполняться. Если нет изменений в a
или b
, useMemo
не запустится и вместо этого вернет сохраненный результат.
Это может быть оптимальным, если обернутая функция невероятно дорога.
Давайте посмотрим на пример из реального мира:
const complexList = React.useMemo(() =>
list.map(item => ({
...item,
expensiveValueOne: expensiveFunction(props.first),
expensiveValue2: anotherPriceyFunction(props.second)
})), [list]
)
В этом случае мы используем ловушку useMemo
для преобразования списка в список объектов. При первом рендеринге эта функция будет запущена, блокируя основной поток. Однако при каждом последующем рендеринге, если list
не изменится, мы можем повторно использовать то же значение и больше не запускать дорогостоящие функции.
Когда использовать useMemo
Выполняя любую оптимизацию React, убедитесь, что вы полностью написали и исправили код, чтобы увидеть, можете ли вы его оптимизировать. useMemo
может действительно снизить производительность при неправильном использовании.
Профилирование вашего приложения React может быть отличным способом гарантировать ощутимый эффект от внедрения useMemo
,
Правильный крюк для работы
useMemo
— не единственный перехватчик React, есть еще useCallback
, useRef
и useEffect
.
Хук useCallback
, о котором я написал статью, очень похож на useMemo
, но возвращает мемоизированную функцию вместо мемоизированного значения.
Если ваш массив зависимостей пуст или содержит значения, которые меняются при каждом рендеринге, useMemo
не сможет правильно запоминать значения и не будет прироста производительности.
Не используйте useMemo
для отключения каких-либо асинхронных значений, вместо этого вы должны использовать useEffect
, useMemo
следует использовать с чистыми функциями.
Заключение
Хук useMemo
может быть невероятно мощным для повышения производительности ваших приложений React при правильном использовании. Запомнив дорогостоящую функцию, мы можем сохранить выходное значение и заставить эту функцию запускаться мгновенно. Однако useMemo
добавляет свои накладные расходы, и его следует использовать только в том случае, если есть явное преимущество оптимизации.
Не пропадай
Там много контента, и я ценю, что вы читаете мой. Я студентка бакалавриата Калифорнийского университета в Беркли по программе MET и молодой предприниматель. Я пишу о разработке программного обеспечения, стартапах и неудачах (в чем я довольно разбираюсь). Вы можете подписаться на мою рассылку здесь или узнать, над чем я работаю, на моем сайте.
Не стесняйтесь обращаться ко мне и связываться со мной в Linkedin или Twitter, я люблю слышать от людей, которые читают мои статьи