Мемоизация — это метод оптимизации, аналогичный кэшированию. Он работает, сохраняя предыдущие результаты вызова функции и используя эти результаты при следующем запуске функции. Это особенно полезно в приложениях с большим объемом вычислений, которые повторяют вызовы функций для одних и тех же параметров.
Вы можете использовать мемоизацию в простом JavaScript, а также в React несколькими различными способами.
Мемоизация в JavaScript
Чтобы запомнить функцию в JavaScript, вам нужно сохранить результаты этой функции в кеше. Кэш может быть объектом с аргументами в качестве ключей и результатами в качестве значений.
Когда вы вызываете эту функцию, она сначала проверяет, присутствует ли результат в кеше перед запуском. Если это так, он возвращает кэшированные результаты. В противном случае он выполняется.
Рассмотрим эту функцию:
функцияплощадь(число) {
возвращаться число * число
}
Функция принимает аргумент и возвращает его квадрат.
Чтобы запустить функцию, вызовите ее с таким номером:
площадь(5) // 25
С 5 в качестве аргумента Square() будет работать довольно быстро. Однако, если бы вы вычислили квадрат 70 000, была бы заметная задержка. Ненамного, но все же с задержкой. Теперь, если бы вы вызывали функцию несколько раз и передавали 70 000, вы бы столкнулись с задержкой при каждом вызове.
Устранить эту задержку можно с помощью мемоизации.
константа memoizedSquare = () => {
позволять тайник = {};
возвращаться (число) => {
если (число в тайник) {
console.log('Повторное использование кэшированного значения');
возвращаться тайник[число];
} еще {
console.log('Расчет результата');
позволять результат = число * число;
// тайник в новыйрезультатценностьзаследующийвремя
тайник[число] = результат;
возвращаться результат;
}
}
}
В этом примере функция проверяет, был ли результат вычислен ранее, проверяя, существует ли он в объекте кеша. Если он есть, он возвращает уже вычисленное значение.
Когда функция получает новое число, она вычисляет новое значение и сохраняет результаты в кеше перед возвратом.
Опять же, этот пример довольно прост, но он объясняет, как мемоизация может работать для повышения производительности программы.
Вы должны запоминать только чистые функции. Эти функции возвращают один и тот же результат при передаче одних и тех же аргументов. Если вы используете мемоизацию для нечистых функций, вы не улучшите производительность, но увеличите свои накладные расходы. Это потому, что вы выбираете скорость вместо памяти каждый раз, когда запоминаете функцию.
Мемоизация в React
Если вы хотите оптимизировать компоненты React, React обеспечивает запоминание через хук useMemo(), React.memo и useCallBack().
Использование useMemo()
useMemo() — это Реагировать крючок который принимает функцию и массив зависимостей.
константа memoizedValue = useMemo(() => calculateExpensiveValue (a, b), [a, b]);
Он запоминает значение, возвращаемое этой функцией. Значения в массиве зависимостей определяют, когда функция выполняется. Только когда они изменяются, функция выполняется снова.
Например, следующий компонент приложения имеет запоминаемое значение с именем result.
импорт { useMemo } из "реагировать"
функцияПриложение(ценность) {
константа квадрат = (значение) => {
возвращаться значение * значение
}
константа результат = использоватьMemo(
() => квадрат (значение),
[ ценность ]
);
возвращаться (
<див>{результат (5)}</div>
)
}
Компонент приложения вызывает Square() при каждом рендеринге. Производительность ухудшится, если компонент приложения будет отображаться много раз из-за Реагировать на реквизит изменение или обновление состояния, особенно если функция Square() дорогая.
Однако, поскольку useMemo() кэширует возвращаемые значения, квадратная функция не выполняется при каждом повторном рендеринге, если не изменяются аргументы в массиве зависимостей.
Использование React.memo()
React.memo() — это компонент более высокого порядка, который принимает компонент React и функцию в качестве аргументов. Функция определяет, когда компонент должен быть обновлен.
Эта функция необязательна, и если она не указана, React.memo выполняет поверхностное сравнение текущих реквизитов компонента с его предыдущими реквизитами. Если реквизиты отличаются, он запускает обновление. Если реквизиты одинаковы, он пропускает повторный рендеринг и повторно использует запомненные значения.
Необязательная функция принимает предыдущие реквизиты и следующие реквизиты в качестве аргументов. Затем вы можете явно сравнить эти реквизиты, чтобы решить, обновлять компонент или нет.
Реагировать.memo(Составная часть, [areEqual (prevProps, nextProps)])
Давайте сначала рассмотрим пример без необязательного аргумента функции. Ниже находится компонент под названием «Комментарии», который принимает реквизиты имени и адреса электронной почты.
функцияКомментарии ({имя, комментарий, лайки}) {
возвращаться (
<див>
<п>{имя}</п>
<п>{комментарий}</п>
<п>{нравится}</п>
</div>
)
}
Компонент мемоизированных комментариев будет иметь React.memo, обернутый вокруг него следующим образом:
константа MemoizedComment = React.memo (комментарий)
Вы можете вызвать его, а затем вызвать его, как любой другой компонент React.
<Имя мемоизированного комментария ="Мэри" комментарий ="Мемоизация — это здорово" нравится=1/>
Если вы хотите выполнить сравнение реквизита самостоятельно, передайте следующую функцию в React.memo в качестве второго аргумента.
импорт Реагировать из "реагировать"
функцияcheckCommentProps(предпропс, следующийпропс) {
возвращаться prevProps.name nextProps.name
&& предыдущийProps.comment следующийProps.comment
&& prevProps.likes nextProps.likes
}
константа MemoizedComment = React.memo (Комментарии, checkCommentProps)
Если checkProfileProps возвращает значение true, компонент не обновляется. В противном случае он перерисовывается.
Пользовательская функция полезна, когда вы хотите настроить повторный рендеринг. Например, вы можете использовать его для обновления компонента «Комментарии» только при изменении количества лайков.
В отличие от хука useMemo(), который запоминает только возвращаемое значение функции, React.memo запоминает всю функцию.
Используйте React.memo только для чистых компонентов. Кроме того, чтобы снизить затраты на сравнение, запоминайте только те компоненты, свойства которых часто меняются.
Использование useCallBack()
Вы можете использовать хук useCallBack() для запоминания функциональные компоненты.
константа memoizedCallback = использоватьCallback(
() => {
сделать что-нибудь (а, б);
},
[а, б],
);
Функция обновляется только при изменении значений в массиве зависимостей. Хук работает так же, как обратный вызов useMemo(), но он запоминает компонент функции между рендерами вместо того, чтобы запоминать значения.
Рассмотрим следующий пример мемоизированной функции, которая вызывает API.
импорт { useCallback, useEffect } из "реагировать";
константа Компонент = () => {
константа getData = useCallback(() => {
console.log('вызвать API');
}, []);
использовать эффект (() => {
получить данные();
}, [получить данные]);
};
Функция getData(), вызываемая в useEffect, будет вызываться снова только при изменении значения getData.
Стоит ли запоминать?
Из этого руководства вы узнали, что такое мемоизация, ее преимущества и способы ее реализации в JavaScript и React. Однако вы должны знать, что React уже работает быстро. В большинстве случаев запоминание компонентов или значений увеличивает затраты на сравнение и не повышает производительность. Из-за этого запоминайте только дорогие компоненты.
В React 18 также появились новые хуки, такие как useId, useTransition и useInsertionEffect. Вы можете использовать их для повышения производительности и взаимодействия с пользователем приложений React.