Зачем нужна мемоизация в React?
Рендеринг и производительность
Мемоизация в React нужна из-за двух особенностей его модели: рендер каскадом (родитель обновился — рендерится всё поддерево) и сравнение по ссылкам (новый объект = «изменилось»).
Проблема, которую решает
const Page = () => {
const [query, setQuery] = useState('');
return (
<>
<SearchInput value={query} onChange={setQuery} />
<HeavyReport data={reportData} /> {/* рендерится на каждый символ */}
</>
);
};HeavyReport не зависит от query, но перерендеривается при каждом вводе — по умолчанию React не проверяет props.
Три инструмента мемоизации
- React.memo(Component) — кеширует результат рендера: при поверхностно равных props компонент пропускается.
- useMemo(fn, deps) — кеширует значение: дорогие вычисления и стабильные ссылки на объекты/массивы.
- useCallback(fn, deps) — кеширует ссылку на функцию.
Они работают связкой: React.memo на ребёнке бесполезен, если родитель передаёт инлайн-функцию — её ссылка каждый раз новая, поэтому нужен useCallback; аналогично с объектами и useMemo.
const HeavyReport = React.memo(Report);
const Page = () => {
const [query, setQuery] = useState('');
const handleExport = useCallback(() => exportPdf(), []);
return <HeavyReport onExport={handleExport} />;
};Зачем ещё, кроме пропуска рендеров
- Стабильные зависимости эффектов: объект в deps без useMemo перезапускает эффект каждый рендер.
- Дорогие вычисления (сортировка тысяч строк) не повторяются без необходимости.
Мера
Мемоизация — не бесплатна (память + сравнение) и усложняет код. Применять по результатам профилирования; React Compiler (React 19) делает её автоматически.
Коротко для собеседования
Мемоизация борется с лишней работой, порождаемой каскадным рендером и сравнением по ссылкам: React.memo пропускает рендер при тех же props, useMemo кеширует значения и ссылки, useCallback — функции. Работают только связкой; применять точечно после профилирования.