Какие ресурсы потребляет мемоизация и как это влияет на производительность
Что проверяют
Понимаете ли вы, что мемоизация не бесплатна: это обмен памяти и сравнений на пропуск вычислений. Следом обычно спрашивают, когда useMemo или React.memo вредят и как вы проверяли, что мемоизация помогла.
Как отвечать
Разложите цену по ресурсам:
- память: кеш держит результат и аргументы, а значит и всё, на что они ссылаются.
useMemoиuseCallbackхранят одно последнее значение на экземпляр компонента, а самописныйmemoizeнаMapрастёт без ограничений, пока живёт страница; - процессор на каждом рендере:
useMemoсравнивает зависимости черезObject.is,React.memoповерхностно сравнивает все пропсы. Если пропсы меняются каждый раз, вы платите за сравнение и всё равно рендерите; - ключи: если ключ кеша строится через
JSON.stringifyбольших объектов, это может стоить дороже самого вычисления; - сложность кода: массивы зависимостей нужно поддерживать, а устаревшее замыкание в
useCallbackдаёт тихие баги.
Выигрыш появляется в трёх случаях: дорогое вычисление при неизменных данных, стабильная ссылка для дочернего компонента в React.memo, стабильная зависимость для useEffect. В остальных мемоизация чаще нейтральна или вредна.
Для кешей вне React задайте ограничение: LRU с лимитом размера или WeakMap, где запись исчезает вместе с ключом-объектом. На useMemo нельзя строить логику: документация React называет его оптимизацией, и кеш может быть сброшен.
Проверяйте замером: React DevTools Profiler покажет, сколько длится рендер и почему компонент перерисовался. Упомяните и React Compiler: он расставляет мемоизацию автоматически при сборке, и ручные useMemo в проектах с ним нужны заметно реже.
Где спотыкаются
Оборачивают всё в useMemo и useCallback на всякий случай. useCallback без React.memo у дочернего компонента не даёт ничего, кроме лишнего сравнения.
Передают в мемоизированный компонент литерал объекта или стрелочную функцию прямо в JSX. Ссылка новая на каждом рендере, и React.memo бесполезен.
Пишут свой кеш на Map по id и забывают про очистку. В долгоживущем SPA это обычная утечка памяти, которую потом находят по снимкам кучи в DevTools.