Что такое React Compiler (стабилен в React 19) и как он меняет ручную мемоизацию?
React Compiler — статический AOT-плагин (Babel/SWC), который анализирует компоненты и хуки, выводит зависимости и автоматически вставляет мемоизацию. В типичном проекте useMemo/useCallback/React.memo становятся почти не нужны: компилятор делает это точнее и не хуже разработчика вручную.
Разбор
React Compiler — это AOT-плагин (Babel/SWC), поставляемый как babel-plugin-react-compiler и стабилизированный в React 19. Он читает функциональные компоненты и кастомные хуки, строит control-flow граф, выводит зависимости каждого выражения и переписывает код так, чтобы значения с неизменившимися зависимостями повторно использовались между рендерами. Это устраняет главную причину, по которой команды раньше засыпали код useMemo/useCallback.
Что компилятор делает внутри
Для каждого компонента компилятор:
- Строит SSA-форму (Static Single Assignment) для отслеживания зависимостей.
- Определяет «реактивные» значения — те, что зависят от props, state или контекста.
- Оборачивает стабильные вычисления в эквивалент
useMemoс автоматически выведенными зависимостями. - Стабилизирует колбэки — эквивалент
useCallbackбез ручного списка зависимостей. - Применяет аналог
React.memoк дочерним JSX-элементам, чтобы стабильные ссылки реально пропускали рендер потомков.
Если компилятор не уверен в чистоте функции — он просто не оптимизирует её. Отказ безопасен: код работает как раньше, только без кэширования.
Пример
// До: разработчик вручную контролирует зависимости
const items = useMemo(() => list.filter(byQuery(q)), [list, q]);
const onSelect = useCallback((id: string) => setSelected(id), []);
// После React Compiler: идиоматический JS без ручной мемоизации
// Компилятор сам определит, что items зависит от list и q,
// а onSelect — стабильная функция
const items = list.filter(byQuery(q));
function onSelect(id: string) {
setSelected(id);
}
Интеграция
# Next.js (встроено в 15+)
# next.config.ts
experimental: { reactCompiler: true }
# Vite
npm install babel-plugin-react-compiler
# vite.config.ts → plugins: [react({ babel: { plugins: ['babel-plugin-react-compiler'] } })]
# ESLint-плагин для диагностики нарушений React Rules
npm install eslint-plugin-react-compiler
ESLint-плагин eslint-plugin-react-compiler подсвечивает участки, мешающие оптимизации: мутации входных массивов, нарушения правил хуков, условные вызовы хуков.
Подводные камни
- Скрытые мутации ломают компилятор. Если компонент мутирует props или внешний объект во время рендера, компилятор либо откажется от оптимизации, либо закэширует неправильный результат. Перед включением прогоните
eslint-plugin-react-compiler. - Компилятор не ускоряет DOM, сеть и layout-эффекты. Он оптимизирует только render-фазу. Медленные
useEffectи тяжёлые layout-вычисления остаются вашей ответственностью. - Не удаляйте
React.memoиuseMemoскопом. На участках, где компилятор отказался оптимизировать (нарушение React Rules), ручная мемоизация остаётся единственной защитой. Удаление без проверки профайлером создаст регрессии. - Классовые компоненты не поддерживаются. Компилятор работает только с функциональными компонентами. Наличие в кодовой базе классовых компонентов не сломает сборку, но они не получат оптимизации.
- Постепенное включение безопаснее. Включайте по директиве
'use memo'на файл или директорию, наблюдайте Performance Profiler в production, потом расширяйте охват. Резкое включение на весь монорепо с legacy-кодом рискованно. - Не путайте с RSC. React Compiler и React Server Components — независимые механизмы с разными задачами. Компилятор оптимизирует render-фазу клиентских компонентов; RSC устраняет их клиентский JS полностью. Они хорошо работают вместе.
- Отладка становится сложнее. Сгенерированный код читается труднее оригинального. В DevTools Profiler можно видеть «memoized» компоненты, но понять, почему конкретная функция не закэширована, без знания правил компилятора сложно.
- Версия React строго 19+. Если в монорепо есть пакеты с peer dependency
react: "^18", компилятор может конфликтовать с ними до обновления зависимостей.
Common mistakes
- Считать, что компилятор всё исправит, и не править нарушения правил React.
- Удалять
useMemo/useCallbackбез прогонки тестов и профилировщика. - Игнорировать
eslint-plugin-react-compiler-предупреждения.
What the interviewer is testing
- Может ли описать, какие правила должен соблюдать код.
- Знает ли, что компилятор может отказаться оптимизировать модуль.
- Понимает ли, что RSC и компилятор — разные вещи.