Как оптимизировать React компонент, чтобы Child компонент не перерендеривался при вводе текста?
Что проверяют
Понимаете ли вы, почему Child вообще перерисовывается: при каждом нажатии клавиши меняется состояние родителя, и React по умолчанию рендерит всё его поддерево. Интервьюер ждёт, что вы начнёте со структуры компонентов, а не с memo на всём подряд. Следом часто спрашивают, как вы убедились, что проблема есть.
Как отвечать
Способы в порядке предпочтения:
- опустить состояние вниз: вынести
inputи егоuseStateв отдельный компонент. Тогда при вводе рендерится только он, а Child вне его поддерева не трогается; - передать Child через
children: компонент с состоянием принимает Child пропсом. Элемент создан выше, его ссылка между рендерами не меняется, и React пропускает поддерево; React.memo: если структуру менять нельзя. Работает только при стабильных пропсах: функции черезuseCallback, объекты черезuseMemoили вынесенные наружу константы;- неуправляемый ввод: если значение нужно только при отправке, хватит
refилиFormData, и состояние на каждый символ не нужно.
Если Child зависит от введённого текста, например фильтрует тяжёлый список, запретить рендер нельзя по смыслу. Тут помогает useDeferredValue, который делает обновление Child низкоприоритетным и не блокирует ввод, или debounce.
Упомяните React Compiler: он мемоизирует компоненты и значения на этапе сборки, и с ним ручные useMemo и useCallback почти не нужны. Проверяйте результат в профайлере React DevTools, там видно, кто рендерится и почему.
Где спотыкаются
Оборачивают Child в memo, но передают ему стрелочную функцию или объект, созданные прямо в JSX. Каждый рендер даёт новую ссылку, и мемоизация не срабатывает. То же с children у мемоизированного компонента и с контекстом, чьё значение пересоздаётся.
Передают в Child само значение поля и удивляются, что memo не помогает. Пропс действительно меняется, такой рендер правильный.
Отвечают через классы и shouldComponentUpdate или оборачивают сеттер из useState в useCallback. Сеттер и так стабилен, а классовые компоненты в новом коде почти не пишут.