Сравни способы оптимизации в React и объясни, когда выбирать каждый вариант.
Рендеринг и производительность
Оптимизация в React сводится к трём направлениям: меньше лишних рендеров, дешевле каждый рендер, меньше и позже грузим код. Выбор инструмента зависит от того, что именно тормозит.
Мемоизация рендеров
React.memo(Component)— пропускает перерендер, если props не изменились. Выбирать для «листовых» компонентов, которые часто получают те же props (строки таблиц, карточки).useMemo— кеширует дорогое вычисление или ссылку на объект. Выбирать при тяжёлых преобразованиях данных и для стабильных ссылок в props/зависимостях.useCallback— стабильная ссылка на функцию. Работает в паре с React.memo у детей.
memo, useMemo и useCallback работают только вместе: один «нестабильный» проп ломает всю цепочку.
Архитектурные приёмы (часто эффективнее мемоизации)
- Спуск состояния вниз — держать часто меняющийся state в маленьком компоненте, а не в корне.
- children как проп — обёртка со state не перерендеривает переданных детей:
const ScrollTracker = ({ children }) => {
const [offset, setOffset] = useState(0);
// children не перерендериваются при изменении offset
return <div onScroll={(e) => setOffset(e.target.scrollTop)}>{children}</div>;
};- Разделение контекстов — отдельные контексты для редко и часто меняющихся данных.
Большие списки и отложенная работа
- Виртуализация (react-window, react-virtuoso) — рендерить только видимые строки. Выбирать при сотнях+ элементов.
useDeferredValue/useTransition(React 18) — пометить обновление как несрочное, чтобы ввод не «замерзал» при тяжёлой перерисовке.
Загрузка кода
React.lazy+Suspense— код-сплиттинг по маршрутам и тяжёлым виджетам.
Коротко для собеседования
Сначала измерить (React DevTools Profiler), потом лечить: лишние рендеры — memo/useCallback/useMemo и правильная структура состояния; тяжёлые списки — виртуализация; блокирующий ввод — useTransition/useDeferredValue; большой бандл — React.lazy. Мемоизация — не по умолчанию везде, а точечно по результатам профилирования.