С каким хуком обычно используют Memo
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какой хук обычно используют с memo?
Наиболее частый и естественный спутник React.memo — это хук useMemo. Эти две оптимизации работают в тандеме для предотвращения лишних ререндеров компонентов, но решают задачи на разных уровнях: memo оптимизирует перерисовку целого компонента, а useMemo — вычисление значений внутри него.
Однако связка с useCallback также крайне важна. Давайте разберем оба случая подробно.
1. useMemo — для мемоизации значений и сложных вычислений
React.memo сравнивает пропсы компонента поверхностно (shallow compare). Если в пропсах передаются вычисленные значения (массивы, объекты), создаваемые заново при каждом рендере родителя, memo не сработает — пропсы будут считаться разными. Здесь нужен useMemo.
import React, { useMemo, memo } from 'react';
const ExpensiveChildComponent = memo(({ items, filterValue }) => {
// Допустим, фильтрация очень дорогая
const filteredItems = useMemo(() => {
console.log('Выполняется тяжелая фильтрация...');
return items.filter(item => item.includes(filterValue));
}, [items, filterValue]); // Пересчитываем только при изменении items или filterValue
return (
<ul>
{filteredItems.map(item => <li key={item}>{item}</li>)}
</ul>
);
});
function ParentComponent() {
const [items] = useState(['Apple', 'Banana', 'Cherry']);
const [filter, setFilter] = useState('');
// Без useMemo этот объект создавался бы заново каждый рендер, и memo не работал бы
const config = useMemo(() => ({
items,
filterValue: filter,
theme: 'dark'
}), [items, filter]);
return <ExpensiveChildComponent {...config} />;
}
Ключевой момент: useMemo внутри мемоизированного компонента (memo) защищает от лишних вычислений внутри компонента, а также помогает стабилизировать сложные пропсы, передаваемые вниз дочерним компонентам.
2. useCallback — для мемоизации функций
Это самая критичная связка. Чаще всего React.memo ломается из-за того, что в пропсах передаются колбэки, создаваемые заново при каждом рендере родителя.
import React, { useState, memo, useCallback } from 'react';
const Button = memo(({ onClick, label }) => {
console.log(`Рендер кнопки: ${label}`);
return <button onClick={onClick}>{label}</button>;
});
function ParentComponent() {
const [count, setCount] = useState(0);
// БЕЗ useCallback: при каждом рендере Parent создается новая функция
// Button (обернутый в memo) будет перерисовываться каждый раз!
// const handleIncrement = () => setCount(c => c + 1);
// С useCallback: функция стабилизируется, memo может предотвратить ререндер
const handleIncrement = useCallback(() => setCount(c => c + 1), []);
return (
<div>
<p>Count: {count}</p>
<Button onClick={handleIncrement} label="Increment" />
</div>
);
}
Итог: Когда и что использовать
React.memo+useCallback— обязательная комбинация, когда вы передаете функции как пропсы в мемоизированный дочерний компонент. БезuseCallbackмемоизация компонента (memo) практически бесполезна.React.memo+useMemo— используется в двух сценариях:
1. Когда внутри мемоизированного компонента есть **ресурсоемкие вычисления**, которые не должны повторяться при каждом ререндере (даже если компонент и перерисовывается).
2. Когда вы передаете в мемоизированный компонент **сложные объекты или массивы** в качестве пропсов. `useMemo` стабилизирует ссылку на этот объект.
Важное предупреждение
Не стоит оборачивать в memo и useMemo/useCallback все подряд. Оптимизация имеет свою стоимость (сравнение пропсов, выделение памяти). Используйте эти инструменты осознанно:
- Когда компонент часто ререндерится с одними и теми же пропсами.
- Когда рендер компонента действительно тяжелый (содержит много элементов, сложную логику).
- Когда компонент является «бутылочным горлышком», определенным с помощью профилировщика React DevTools.
Правильный подход — сначала написать чистый код без оптимизаций, а затем, при необходимости, добавить memo и соответствующие хуки, основываясь на данных профилирования.