Какие техники мемоизации и кэширования используются для оптимизации производительности при частых обновлениях данных
Что проверяют
Отличаете ли вы мемоизацию вычислений от кэширования серверных данных и умеете ли держать кэш свежим, когда данные меняются каждую секунду. Следом почти всегда спрашивают про инвалидацию: кто, когда и по какому ключу сбрасывает кэш.
Как отвечать
Разложите ответ по уровням:
- мемоизация в компонентах:
useMemoдля дорогих производных значений,useCallbackдля стабильных ссылок на обработчики,React.memo, чтобы потомок не перерисовывался при тех же пропсах. Сравнение идёт поObject.is, поэтому новый объект или массив в пропсах на каждом рендере обнуляет всю пользу; - селекторы:
createSelectorв Redux Toolkit,useShallowв Zustand. Компонент подписывается на свой срез стора и не рендерится от чужих изменений; - кэш серверных данных: TanStack Query или RTK Query. Кэш по ключу запроса,
staleTimeиgcTime, дедупликация одинаковых запросов,invalidateQueriesпосле мутации,setQueryDataдля точечной правки из WebSocket; - HTTP:
Cache-Control,ETag, стратегия stale-while-revalidate.
Для частых обновлений (котировки, чат, дашборд) добавьте нормализацию, чтобы обновлялась одна сущность, а не весь список, троттлинг потока событий и виртуализацию длинных списков. Упомяните React Compiler: он расставляет мемоизацию сам, и ручные useMemo в таком проекте часто лишние.
Где спотыкаются
Мемоизируют всё подряд без замеров. На дешёвом вычислении useMemo стоит дороже самого вычисления, а узкое место сначала ищут в React DevTools Profiler.
Пишут самодельный memoize с проверкой if (cache[key]): результат 0 или пустая строка никогда не попадёт в кэш, а без лимита и LRU кэш растёт бесконечно.
Кладут ответы API в localStorage без срока жизни и версии. Данные устаревают навсегда, доступ синхронный и блокирует основной поток, а при частых обновлениях такой кэш только мешает.