Какие последствия отсутствия мемоизации для производительности и UX
Что проверяют
Понимаете ли вы, откуда в React берутся лишние рендеры и когда мемоизация нужна, а когда лишняя. Следом почти наверняка спросят про разницу useMemo и useCallback и про то, что меняет React Compiler.
Как отвечать
Сначала механика. Компонент перерисовывается при изменении своего состояния и при каждом рендере родителя, даже если пропсы те же. Сам ререндер дёшев, проблемы начинаются в трёх случаях:
- дорогие вычисления в рендере: фильтрация и сортировка списка на тысячи элементов на каждое нажатие клавиши. Лечится
useMemoили переносом вычисления; - каскад по дереву: изменение состояния наверху перерисовывает большое поддерево.
React.memoотсекает ребёнка, если пропсы не изменились при поверхностном сравнении; - нестабильные ссылки: объект или функция, созданные в рендере, каждый раз новые. Они ломают
React.memoу ребёнка и перезапускаютuseEffect, в зависимостях которого стоят. Тут нужныuseCallbackиuseMemo.
Последствия для пользователя измеримы. Долгие задачи на главном потоке (дольше 50 мс) задерживают отклик, поле ввода «залипает», прокрутка дёргается. В метриках это ухудшает INP, которая с 2024 года входит в Core Web Vitals; хорошим считается значение до 200 мс.
Покажите, что сначала измеряете: React DevTools Profiler с подсветкой рендеров, вкладка Performance в браузере. Назовите и альтернативы мемоизации: опустить состояние ниже по дереву, передавать тяжёлые части через children, виртуализировать длинные списки, использовать селекторы с createSelector в Redux.
Отдельно упомяните React Compiler: он расставляет мемоизацию автоматически на этапе сборки, и в проектах с ним ручные useMemo нужны заметно реже.
Где спотыкаются
Оборачивают всё подряд в useMemo и useCallback. Сравнение зависимостей и хранение значений тоже стоят ресурсов, а код становится шумным.
Ставят React.memo, но передают ребёнку инлайн-функцию или объект-литерал. Мемоизация не срабатывает ни разу.
Считают useMemo гарантией. По документации это оптимизация, React вправе сбросить кэш, поэтому логика, от которой зависит корректность, на нём строиться не должна.