Let me explain for React Сompiler
![](https://habrastorage.org/getpro/habr/upload_files/c27/a6b/eb0/c27a6beb012626d7fad82b9b0286a823.png)
In 2024, the React team is preparing many innovations dedicated to the release React 19.
One of these innovations is React Compiler – a new JavaScript compiler to optimize calculations. The main goal of the developers was to optimize and automate memoization in React applications. Previously, front-end developers had to use hooks like useCallback
And useMemo
then React will soon take responsibility for memoization itself to avoid re-computations on every render.
Let’s not delay the introduction and move straight to the retelling.
Principle of operation
As already mentioned, React Compiler is a build tool that automatically optimizes your React application. It works like an advanced memoization downloader out of the box, automatically setting up memoization in the application.
React currently requires manual management of render optimization using the API useMemo()
, useCallback()
And memo
. The new React compiler will take control of these things, automatically determining how and when to change state and update the UI.
This means developers no longer need to manually use useMemo()
, useCallback()
And memo
, since React Compiler will take care of the optimization itself. Therefore, the need to use useMemo()
, useCallback()
And memo
will be significantly reduced, freeing developers from manually managing optimizations.
Memoization in React before React Compiler: How was it?
Before the advent of React Compiler, memoization in React required developers to manually manage computational optimization. Let's figure out together how this happened using hooks useMemo
And useCallback
.
When you were working on your React applications, you needed to use useMemo
to memoize values. Imagine you have a complex computational process that you don't want to run every time you render components. In such cases you used useMemo
to tell React to “Remember this value and don't recalculate it unless the dependencies have changed.”
Usage example:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
In this example the function computeExpensiveValue
is executed only when a
or b
change. In other cases, React simply returns a cached value, which saves significant resources.
It was used to memoize functions useCallback
. Imagine you have a function that you don't want to recreate every render. you used useCallback
to keep it in memory as long as the dependencies remain unchanged.
Usage example:
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
This strategy meant that the function doSomething
was recreated only when a
or b
changed. This helped avoid unnecessary rendering of components that depended on this function.
However, all this manual work could be tedious and error-prone. You had to track dependencies yourself and configure memoization correctly. With the advent of React Compiler, this task is automated, freeing you from manually managing optimization and allowing you to focus on other aspects of development.
Major improvements to React Compiler (aka React Forget)
Optimizing conditions and side effects
React Forget automatically optimizes the handling of state and side effects in components. The compiler analyzes the code and determines which parts can be memoized or optimized to prevent unnecessary redraws.
Automatic memoization control
The new compiler adds memoization where needed. This means that developers don't have to manually add hooks like
useMemo
oruseCallback
to optimize performance – the compiler decides when it is required.
Smart dependency detection
React Forget automatically determines when to update states and side effects, minimizing unnecessary renders and optimizing performance.
Installation
In the words of the React team itself:
“React Compiler is a new experimental compiler that we have open-sourced to get early feedback from the community. It still has bugs and is not fully ready for production yet.”
However, we have the opportunity to try out the compiler in experimental conditions right now. To do this, you need to use React version 19 RC.
Before installing the compiler itself, I advise you to first check if your codebase is compatible using the command:
npx react-compiler-healthcheck@latest
This script:
Checks how many components can be successfully optimized;
Will check usage
<StrictMode>
: Enabling and enforcing this setting means there is a higher likelihood of following React rules;Will check for use of incompatible libraries, etc.
As an example:
Successfully compiled 8 out of 9 components.
StrictMode usage not found.
Found no usage of incompatible libraries.
In addition, React Compiler also supports the eslint plugin. It can be used regardless from the compiler, meaning you can use the eslint plugin even if you don't use the compiler itself.
npm install eslint-plugin-react-compiler
Then add it to your eslint configuration:
module.exports = {
plugins: [
'eslint-plugin-react-compiler',
],
rules: {
'react-compiler/react-compiler': "error",
},
}
The eslint plugin will display any React rule violations in your editor. When it does this, it means the compiler missed optimizing that component or hook.
Existing projects
The compiler is designed to compile functional components and hooks that follow the rules of React. It can also handle code that violates these rules by freeing (passing) these components or interceptors.
“For this reason, to successfully use the compiler on existing projects, we recommend that you first run it in a small directory of your product's code. You can do this by configuring the compiler to run only in a specific set of directories.” – Reported by the React team.
const ReactCompilerConfig = {
sources: (filename) => {
return filename.indexOf('src/path/to/dir') !== -1;
},
};
In rare cases, you can also configure the compiler to run in “annotation” mode using compilationMode: "annotation"
. This means that the compiler will only compile components and interceptors annotated with the directive "use memo"
.
const ReactCompilerConfig = {
compilationMode: "annotation",
};
// src/app.jsx
export default function App() {
"use memo";
// ...
}
This annotation mode is temporary and intended to help early adopters, so developers do not plan to use"use memo"
directive in the long term.
New projects
As an installation for new projects, React Compiler will have a wide range of installation and configuration options:
Babel
npm install babel-plugin-react-compiler
After installing the plugin, simply add it to your Babel configuration:
// babel.config.js
const ReactCompilerConfig = { /* ... */ };
module.exports = function () {
return {
plugins: [
['babel-plugin-react-compiler', ReactCompilerConfig],
// ...
],
};
};
Vite
To use in conjunction with Vite, make changes to vite.config:
// vite.config.js
const ReactCompilerConfig = { /* ... */ };
export default defineConfig(() => {
return {
plugins: [
react({
babel: {
plugins: [
["babel-plugin-react-compiler", ReactCompilerConfig],
],
},
}),
],
// ...
};
});
Next.js
In the case of Next.js, we have an experimental configuration to enable the React compiler. This automatically ensures that Babel is configured using babel-plugin-react-compiler
.
First, you should install Next.js canary version with React 19 Release Candidate enabled, then install the plugin itself:
npm install next@canary babel-plugin-react-compiler
Then go to edit next.config:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
Webpack
To work with Webpack you will need to create your own loader for the compiler
It should look something like this:
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;
After installation, you can find out which of your components have been optimized. To achieve this, React Devtools (v5.0+) has built-in support for React Compiler and displays a “Memo ✨” icon next to components optimized by the compiler.
To override component optimization, you can use the directive "use no memo"
which allows you to avoid compiling components and hooks with the React compiler for a while.
What's next?
So React Compiler really aims to automate memoization, making life much easier for developers. Now we can only wait for the full release of the compiler. However, it is important to understand that in some cases manual control can still be useful.
Although the release date is constantly being pushed back, I hope to release a stable version as soon as possible. It is also worth considering that with the release of a stable version, some aspects of the installation and configuration of the compiler may change. In this case, I recommend reading the official React documentation.
PS For me, the experience of writing articles is new. Having succumbed to the persuasion of one of my friends, I nevertheless decided to try myself in this field. If you have suggestions for improving the quality of this article, please leave your feedback in the comments.