Что такое pure component и как создать его на примере функционального компонента в React
Что проверяют
Различаете ли вы два разных смысла слова «чистый» в React. Первый это правило: компонент обязан быть чистой функцией своих пропсов и состояния. Второй это оптимизация: пропуск лишнего рендера при неизменившихся пропсах. Кандидаты обычно знают только второй.
Как отвечать
Начните с правила. Чистый компонент при одинаковых входных данных возвращает одинаковый результат и не имеет побочных эффектов во время рендера: не мутирует пропсы, не пишет во внешние переменные, не ходит в сеть. На этом держатся двойной вызов рендера в строгом режиме и конкурентный рендеринг, а всё остальное живёт в эффектах.
Теперь оптимизация. Классовый PureComponent сравнивал поверхностно пропсы и состояние. Функциональный аналог это React.memo, и он сравнивает только пропсы: собственное состояние и контекст вызывают рендер в любом случае.
const Row = React.memo(function Row({ item, onPick }) {
return <li onClick={() => onPick(item.id)}>{item.title}</li>;
});Чтобы обёртка работала, пропсы должны быть стабильны между рендерами родителя. Объекты, массивы и стрелки создаются заново каждый раз, поэтому в паре с memo идут useCallback и useMemo. Вторым аргументом memo принимает свою функцию сравнения.
Сильное завершение: мемоизация не бесплатна, сравнение тоже стоит времени и памяти, поэтому её ставят по результатам профилировщика, а не заранее на каждый компонент.
Где спотыкаются
Говорят, что React.memo сравнивает пропсы и состояние. Состояние он не видит: setState внутри обёрнутого компонента перерисует его всегда, как и изменение значения контекста, на который он подписан.
Оборачивают компонент и тут же передают ему инлайновый объект или стрелку. Поверхностное сравнение каждый раз даёт ложь, рендер происходит как и раньше, а накладные расходы добавились. Та же ловушка с children, переданными элементом: это новый объект на каждом рендере родителя.
Мутируют объект вместо создания нового и получают обратную беду: ссылка прежняя, сравнение считает пропсы равными, и экран не обновляется. Или пишут свою функцию сравнения с глубоким обходом больших данных, которая обходится дороже самого рендера.