Как правильно использовать мемоизацию в React
Что проверяют
Понимаете ли вы, что у мемоизации есть цена, и умеете ли объяснить, когда она действительно нужна.
Как отвечать
Три инструмента: useMemo запоминает результат вычисления, useCallback запоминает саму функцию, React.memo предотвращает перерисовку компонента при неизменных пропсах.
Когда это оправдано:
- дорогое вычисление: сортировка или фильтрация большого списка на каждый рендер;
- ссылочная стабильность: функция или объект передаётся в дочерний компонент, обёрнутый в
memo, или стоит в зависимостяхuseEffect. Без мемоизации новая ссылка на каждый рендер делаетmemoи массив зависимостей бесполезными; - тяжёлое поддерево, которое перерисовывается из-за родителя, хотя его данные не менялись.
Когда не нужно и вредно: простые вычисления (сложить два числа дешевле, чем сравнить зависимости и достать из кэша), компоненты, которые и так редко перерисовываются, обёртывание всего подряд «на всякий случай». Мемоизация занимает память и добавляет проверки на каждый рендер.
Порядок действий правильный такой: сначала замерить профайлером React, где реально тратится время, потом мемоизировать точечно. Часто выясняется, что дело не в вычислениях, а в том, что состояние лежит слишком высоко в дереве, и его достаточно опустить ниже.
Важно добавить про будущее: React Compiler делает эту работу автоматически, и в проектах с ним ручная мемоизация становится лишней.
Где спотыкаются
Оборачивают всё подряд без замеров.
Мемоизируют функцию, но передают её в компонент без memo, и смысла нет.
Забывают зависимость и получают устаревшее замыкание.
Считают, что useMemo гарантирует отсутствие пересчёта: React вправе сбросить кэш.