React

React Compiler: авто-мемоизация

Годами расстановка useMemo и useCallback была ритуалом: разработчик вручную помечал, что можно не пересчитывать, ошибался в массиве зависимостей, ловил баги от устаревших замыканий и тратил на это часы код-ревью. На React Conf в мае 2024 команда показала демо: те же компоненты, но без единой ручной обёртки - и при этом без лишних ре-рендеров. Мемоизацию расставлял компилятор. В октябре 2025 React Compiler вышел как v1.0 stable, и многолетний ручной ритуал начал уходить в историю.

  • Meta: компилятор обкатан в продакшене на Instagram и других веб-приложениях задолго до публичного релиза
  • Команды на Next.js и Vite: подключают плагин компилятора и постепенно удаляют ручные useMemo и useCallback
  • React Native: компилятор работает и там, ускоряя мобильные интерфейсы той же авто-мемоизацией
  • eslint-plugin-react-compiler: статически ловит нарушения Rules of React ещё до сборки, в редакторе
  • Open-source библиотеки компонентов переводят кодовую базу на компилятор, чтобы убрать оптимизационный шум из исходников

Предварительные знания

  • Ручная мемоизация: что делают memo, useMemo и useCallback и зачем нужна стабильность ссылок
  • Базовое понимание этапа сборки фронтенда (Babel или SWC как трансформер кода)
  • Идея чистой функции: одинаковый вход даёт одинаковый выход без побочных эффектов

Путь от ручного ритуала к компилятору

Идея переложить мемоизацию на инструмент обсуждалась в команде React с конца 2010-х под рабочим названием React Forget. Проблема была в том, что безопасно мемоизировать можно только предсказуемый код, а JavaScript позволяет писать как угодно. Решением стал не магический рантайм, а компилятор, который анализирует код на этапе сборки и применяет мемоизацию только там, где код соответствует Rules of React. Первое публичное демо прошло на React Conf в мае 2024, бета вышла позже в том же году, а в октябре 2025 компилятор получил статус v1.0 stable. Параллельно вышел eslint-plugin-react-compiler, который подсвечивает места, где код нарушает правила и потому не может быть безопасно оптимизирован.

Что именно делает компилятор

React Compiler - это не рантайм-библиотека, а трансформер исходного кода. Он встраивается в сборку, разбирает каждый компонент и хук, понимает, какие значения от каких зависят, и генерирует версию кода с автоматической мемоизацией. Результат эквивалентен тому, что аккуратный разработчик расставил бы вручную через memo, useMemo и useCallback - но без человеческих ошибок в массивах зависимостей.

Без компилятора этот код пересчитывал бы filtered и пересоздавал бы дерево при каждом рендере родителя, даже если products и query не менялись. Разработчику пришлось бы обернуть filtered в useMemo и, возможно, ProductCard в memo. Компилятор делает это сам: на этапе сборки он порождает код, который кэширует filtered по products и query и переиспользует прошлый результат, пока зависимости стабильны.

Важно: компилятор не убирает JavaScript и не превращает React в другой инструмент. Он оптимизирует выполнение того же React-кода, добавляя пропуски лишней работы. Бандлинг остаётся за сборщиком, а рантайм React тот же самый.

Подключение обычно сводится к добавлению одного плагина в конфигурацию Babel или SWC (в Next.js это флаг в конфиге, во Vite - плагин). После этого ручные обёртки можно постепенно удалять, а не переписывать всё сразу: компилятор корректно работает и с уже мемоизированным кодом.

Чем React Compiler принципиально отличается от рантайм-оптимизации?

Почему нужны Rules of React

Компилятор может безопасно пропускать вычисление только если уверен, что повторный вызов с теми же входными данными дал бы тот же результат и не имел бы скрытых побочных эффектов. Это и есть суть Rules of React - набор правил, которые делают код предсказуемым. Если компонент во время рендера мутирует props, читает изменяемую глобальную переменную или вызывает хуки в условии, компилятор не может гарантировать корректность мемоизации и либо пропускает такой компонент, либо предупреждает.

  • Компоненты и кастомные хуки должны быть чистыми во время рендера: одинаковый вход даёт одинаковый выход
  • Нельзя мутировать props, state или возвращаемые значения хуков напрямую
  • Побочные эффекты живут в обработчиках событий и в useEffect, а не в теле рендера
  • Хуки вызываются только на верхнем уровне компонента или другого хука, без условий и циклов
  • Соблюдается соглашение об именах: хуки начинаются с use, компоненты с заглавной буквы

Эти правила существовали всегда - просто раньше их нарушение приводило к редким и трудноуловимым багам. С компилятором они становятся условием корректности: мемоизация безопасна ровно настолько, насколько код предсказуем. Поэтому переход на компилятор часто заодно повышает дисциплину кода.

Компилятор консервативен: встретив код, который он не может гарантированно оптимизировать, он не ломает его, а просто оставляет неоптимизированным. То есть включение компилятора не должно ломать работающее приложение - в худшем случае часть компонентов останется без авто-мемоизации до исправления нарушений.

Почему компилятор требует соблюдения Rules of React, чтобы безопасно мемоизировать компонент?

Внедрение, ESLint и React Native

Внедрение начинается не с компилятора, а с линтера. eslint-plugin-react-compiler статически анализирует код и подсвечивает места, где нарушены Rules of React, прямо в редакторе - до сборки. Это позволяет постепенно привести кодовую базу в порядок, а уже потом включать сам компилятор, зная, что он сможет оптимизировать большую часть кода.

ИнструментКогда работаетЧто делает
eslint-plugin-react-compilerВ редакторе и CI, до сборкиНаходит нарушения Rules of React, мешающие оптимизации
Плагин компилятора (Babel/SWC)На этапе сборкиТрансформирует компоненты, добавляя авто-мемоизацию
Рантайм ReactВ браузереИсполняет уже оптимизированный код, пропуская лишнюю работу

После релиза v1.0 в октябре 2025 компилятор перестал быть экспериментом. Он официально поддерживается в основных тулчейнах и работает не только в вебе, но и в React Native: та же авто-мемоизация ускоряет мобильные интерфейсы, где лишние ре-рендеры особенно дороги на слабых устройствах. Рекомендованный путь для новых проектов - включать компилятор сразу и почти не писать ручную мемоизацию.

Что это меняет в повседневной работе: исходный код становится чище, потому что из него уходит оптимизационный шум - десятки useMemo и useCallback, которые маскировали бизнес-логику. Разработчик пишет прямолинейный код, а производительностью занимается компилятор. Ручная мемоизация остаётся как инструмент для редких краевых случаев.

Команда хочет внедрить React Compiler в большой существующий проект. С чего разумнее начать?

Связь с другими темами

Компилятор стоит на плечах предыдущего урока и меняет привычки кодирования:

  • Ручная мемоизация — То, что компилятор делает автоматически. Понимание ручного варианта объясняет, что именно он генерирует
  • Reconciliation — Объясняет, откуда берутся лишние ре-рендеры, которые компилятор устраняет
  • Конкурентный рендеринг — Следующий слой производительности, тоже снимающий ручную работу с разработчика

Итог

  • React Compiler анализирует код на этапе сборки и сам расставляет мемоизацию, эквивалентную ручным memo, useMemo и useCallback
  • Подключается как плагин к Babel или SWC и интегрируется в сборку через Vite, Next.js и другие тулчейны
  • Работает безопасно только при соблюдении Rules of React: компоненты и хуки должны быть чистыми и предсказуемыми
  • eslint-plugin-react-compiler заранее находит нарушения правил, которые помешали бы оптимизации
  • v1.0 stable вышел в октябре 2025, работает в том числе с React Native, и постепенно делает ручную мемоизацию необязательной

Связанные уроки

  • rc-19-memoization — Компилятор автоматизирует ручную мемоизацию, поэтому сначала надо понять, что именно memo, useMemo и useCallback делают вручную
  • rc-17-reconciliation — Чтобы оценить выигрыш компилятора, полезно понимать, как reconciliation порождает лишние ре-рендеры
  • rc-24-concurrent-intro — Ещё один уровень автоматизации производительности: конкурентный рендеринг тоже снимает работу с разработчика
React Compiler: авто-мемоизация

0

1

Войти