Какие причины ререндеринга компонентов остаются после оптимизации с useCallback
Что проверяют
Понимаете ли вы, что useCallback сам по себе ререндер не отменяет, а только сохраняет ссылку на функцию. Интервьюер хочет услышать, от чего на самом деле зависит повторный рендер. Следом обычно просят показать, как найти причину лишнего рендера на конкретном экране.
Как отвечать
Базовое правило: когда рендерится родитель, React по умолчанию рендерит всех его детей, независимо от пропсов. Стабильная ссылка помогает, только если ребёнок обёрнут в React.memo или функция стоит в зависимостях useEffect или useMemo. Что остаётся после оптимизации:
- нет
React.memo: без него стабильный колбэк бесполезен; - другие пропсы новые на каждом рендере:
style={{...}}, массив опций, объект конфигурации прямо в JSX.memoсравнивает пропсы поверхностно, и одного такого пропса хватает; children: переданный внутрь JSX это новый объект на каждом рендере родителя, иmemoу обёртки не срабатывает;- зависимости
useCallback: если в массиве объект, который пересоздаётся, функция тоже каждый раз новая; - контекст: изменение
valueрендерит всех потребителей,memoэто не останавливает. Особенно больно, когдаvalue={{ user, setUser }}собирается заново на каждом рендере провайдера; - собственное состояние:
useStateвнутри кастомного хука, подписка на размер окна, селектор стора, который возвращает новый объект; - смена
key: это уже не ререндер, а размонтирование и новое монтирование.
Найти причину помогает Profiler в React DevTools с включённой записью того, почему компонент отрендерился. В проектах с React Compiler ручную мемоизацию в основном расставляет компилятор, но правила про контекст и стабильность данных остаются.
Где спотыкаются
Оборачивают в useCallback всё подряд без memo у получателя. Кода становится больше, рендеров столько же.
Принимают двойной рендер в разработке за ошибку. Это StrictMode, в продакшн-сборке его нет.
Путают ререндер с обновлением DOM. Если результат рендера не изменился, React не трогает DOM, поэтому оптимизировать стоит то, что профайлер показывает как долгое.