Let me explain for React Сompiler

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 useMemothen 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 useMemoto 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 useCallbackto 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)

  1. 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.

  2. Automatic memoization control

    • The new compiler adds memoization where needed. This means that developers don't have to manually add hooks like useMemo or useCallback to optimize performance – the compiler decides when it is required.

  3. 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *