Поясняю за React Сompiler
В 2024 году команда React готовит множество нововведений, приуроченных к выходу React 19.
Одним из таких нововведений является React Сompiler — новый JavaScript-компилятор для оптимизации вычислений. Главной целью разработчиков была оптимизация и автоматизация мемоизации в React-приложениях. Если раньше фронтендерам приходилось использовать такие хуки, как useCallback
и useMemo
, то вскоре React сам возьмёт на себя ответственность за мемоизацию, чтобы избежать повторных вычислений при каждом рендеринге.
Не будем затягивать со вступлением и сразу перейдём к пересказу.
Принцип работы
Как уже упоминалось, React Compiler — это инструмент сборки, который автоматически оптимизирует ваше React-приложение. Он работает по принципу продвинутого загрузчика с мемоизацией из коробки, автоматически настраивая мемоизацию в приложении.
В настоящее время React требует ручного управления оптимизацией рендеров с использованием API useMemo()
, useCallback()
и memo
. Новый компилятор React возьмёт на себя управление этими вещами, автоматически определяя, как и когда изменять состояние и обновлять пользовательский интерфейс.
Это означает, что разработчикам больше не нужно вручную использовать useMemo()
, useCallback()
и memo
, так как React Compiler сам позаботится об оптимизации. Таким образом, необходимость в использовании useMemo()
, useCallback()
и memo
значительно уменьшится, освобождая разработчиков от ручного управления оптимизациями.
Мемoизация в React до React Compiler: Как это было?
До появления React Compiler, мемоизация в React требовала от разработчиков ручного управления оптимизацией вычислений. Давайте вместе разберёмся, как это происходило с использованием хуков useMemo
и useCallback
.
Когда вы работали над вашими React-приложениями, необходимо было использовать useMemo
для мемоизации значений. Представьте, что у вас есть сложный вычислительный процесс, который вы не хотите запускать при каждом рендере компонентов. В таких случаях вы использовали useMemo
, чтобы указать React: «Запомни это значение и не пересчитывай его, если зависимости не изменились».
Пример использования:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
В этом примере функция computeExpensiveValue
выполняется только тогда, когда a
или b
изменяются. В остальных случаях React просто возвращает кэшированное значение, что значительно экономит ресурсы.
Для мемоизации функций же использовался useCallback
. Представьте, что у вас есть функция, которую вы не хотите пересоздавать при каждом рендере. Вы использовали useCallback
, чтобы держать её в памяти, пока зависимости остаются неизменными.
Пример использования:
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
Эта стратегия означала, что функция doSomething
пересоздавалась только тогда, когда a
или b
изменялись. Это помогало избежать ненужных рендеров компонентов, зависящих от этой функции.
Однако вся эта ручная работа могла быть утомительной и подверженной ошибкам. Вам приходилось самостоятельно отслеживать зависимости и правильно настраивать мемоизацию. С появлением React Compiler эта задача автоматизируется, освободив вас от необходимости вручную управлять оптимизацией и позволяя сосредоточиться на других аспектах разработки.
Основные улучшения React Сompiler (он же React Forget)
Оптимизация состояний и побочных эффектов
React Forget автоматически оптимизирует обработку состояний и побочных эффектов в компонентах. Компилятор анализирует код и определяет, какие части могут быть мемоизированы или оптимизированы для предотвращения лишних перерисовок.
Автоматическое управление мемоизацией
Новый компилятор добавляет мемоизацию там, где это необходимо. Это значит, что разработчикам не нужно вручную добавлять хуки вроде
useMemo
илиuseCallback
для оптимизации производительности — компилятор сам решает, когда это требуется.
Умное определение зависимостей
React Forget автоматически определяет, когда нужно обновлять состояния и побочные эффекты, минимизируя ненужные рендеры и оптимизируя производительность.
Установка
По словам самой команды React:
"React Compiler — это новый экспериментальный компилятор, исходный код которого мы открыли, чтобы заранее получить отзывы от сообщества. Он все еще имеет недочёты и еще не полностью готов к продакшену."
Однако, у нас есть возможность опробовать компилятор в условиях экспериментального использования уже сейчас. Для этого необходимо воспользоваться React'ом версии 19 RC.
Перед установкой самого компилятора, советую сначала проверить, совместима ли ваша кодовая база с помощью команды:
npx react-compiler-healthcheck@latest
Этот скрипт:
Проверит, сколько компонентов можно успешно оптимизировать;
Проверит использование
<StrictMode>
: включение и соблюдение этого параметра означает более высокую вероятность соблюдения правил React;Проверит использование несовместимых библиотек и т.д.
В качестве примера:
Successfully compiled 8 out of 9 components.
StrictMode usage not found.
Found no usage of incompatible libraries.
Помимо этого, React Сompiler также поддерживает плагин eslint. Его можно использовать независимо от компилятора, то есть вы можете использовать плагин eslint, даже если вы не используете сам компилятор.
npm install eslint-plugin-react-compiler
Затем добавьте его в свою конфигурацию eslint:
module.exports = {
plugins: [
'eslint-plugin-react-compiler',
],
rules: {
'react-compiler/react-compiler': "error",
},
}
Плагин eslint будет отображать любые нарушения правил React в вашем редакторе. Когда он это делает, это означает, что компилятор пропустил оптимизацию этого компонента или хука.
Существующие проекты
Компилятор предназначен для компиляции функциональных компонентов и хуков, соответствующих правилам React. Он также может обрабатывать код, который нарушает эти правила, освобождая (пропуская) эти компоненты или перехватчики.
"По этой причине, чтобы успешно использовать компилятор в существующих проектах, мы рекомендуем сначала запустить его в небольшом каталоге кода вашего продукта. Вы можете сделать это, настроив компилятор для запуска только в определенном наборе каталогов" - Сообщает команда React.
const ReactCompilerConfig = {
sources: (filename) => {
return filename.indexOf('src/path/to/dir') !== -1;
},
};
В редких случаях вы также можете настроить компилятор для работы в режиме «аннотации», используя compilationMode: "annotation"
. Это означает, что компилятор будет компилировать только компоненты и перехватчики, аннотированные директивой "use memo"
.
const ReactCompilerConfig = {
compilationMode: "annotation",
};
// src/app.jsx
export default function App() {
"use memo";
// ...
}
Этот режим аннотации является временным и предназначен для помощи ранним пользователям, поэтому разработчики не планируют использовать"use memo"
директиву в долгосрочной перспективе.
Новые проекты
В качестве установки на новые проекты, React Сompiler будет иметь широкий выбор вариантов установки и настройки:
Babel
npm install babel-plugin-react-compiler
После установки плагина просто добавьте его в свою Babel конфигурацию :
// babel.config.js
const ReactCompilerConfig = { /* ... */ };
module.exports = function () {
return {
plugins: [
['babel-plugin-react-compiler', ReactCompilerConfig],
// ...
],
};
};
Vite
Для использования в связке с Vite внесите изменения в vite.config:
// vite.config.js
const ReactCompilerConfig = { /* ... */ };
export default defineConfig(() => {
return {
plugins: [
react({
babel: {
plugins: [
["babel-plugin-react-compiler", ReactCompilerConfig],
],
},
}),
],
// ...
};
});
Next.js
В случае с Next.js мы имеем экспериментальную конфигурацию для включения компилятора React. Это автоматически гарантирует, что Babel настроен с использованием babel-plugin-react-compiler
.
Для начала стоит установить Next.js canary версию с включенным React 19 Release Candidate, затем поставьте сам плагин:
npm install next@canary babel-plugin-react-compiler
После чего перейдите к редактированию next.config:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
Webpack
Для работы с Webpack потребуется создать собственный лоадер для компилятора
Выглядеть это должно примерно так:
const ReactCompilerConfig = { /* ... */ };
const BabelPluginReactCompiler = require('babel-plugin-react-compiler');
function reactCompilerLoader(sourceCode, sourceMap) {
// ...
const result = transformSync(sourceCode, {
// ...
plugins: [
[BabelPluginReactCompiler, ReactCompilerConfig],
],
// ...
});
if (result === null) {
this.callback(
Error(`Failed to transform "${options.filename}"`)
);
return;
}
this.callback(
null,
result.code
result.map === null ? undefined : result.map
);
}
module.exports = reactCompilerLoader;
После установки вы можете узнать, какие из ваших компонентов были оптимизированы. Для этого React Devtools (v5.0+) имеет встроенную поддержку React Compiler и отображает значок «Memo ✨» рядом с компонентами, оптимизированными компилятором.
Чтобы отменить оптимизацию компонентов, вы можете использовать директиву "use no memo"
, которая позволяет вам отказаться от компиляции компонентов и хуков компилятором React на некоторое время.
Что дальше?
Таким образом, React Compiler действительно направлен на автоматизацию мемоизации, значительно облегчая жизнь разработчикам. Сейчас нам остаётся лишь ждать полноценного выпуска компилятора. Тем не менее, важно понимать, что в некоторых случаях ручное управление всё ещё может быть полезным.
Хотя дата релиза постоянно переносится, я надеюсь на скорейший выпуск стабильной версии. Стоит также учитывать, что с выпуском стабильной версии некоторые аспекты установки и настройки компилятора могут измениться. В этом случае, рекомендую ознакомиться с официальной документацией React.
P.S. Для меня опыт написания статей является новым. Поддавшись уговорам одного своего приятеля, я всё же решил попробовать себя на этом поприще. Если у вас есть предложения по улучшению качества данной статьи, прошу оставить свой отзыв в комментариях.