We use cookies to enhance your experience on the site
CodeWorlds

React Compiler (React Forget)

Imagine that on your spaceship, instead of manually configuring every optimization system, you have an intelligent autopilot that automatically detects and optimizes all redundant operations. That is exactly what the React Compiler (also known as React Forget) does -- it automatically analyzes your code and adds memoization where it is needed.

The Problem: Manual Memoization

Until now, performance optimization in React required manual use of

React.memo
,
useMemo
, and
useCallback
. It is like manually configuring every system on a spaceship -- time-consuming, error-prone, and easy to overlook:

1// BEFORE React Compiler - manual memoization
2import { useState, useMemo, useCallback, memo } from 'react';
3
4const MissionCard = memo(function MissionCard({ mission, onSelect }) {
5  return (
6    <div onClick={() => onSelect(mission.id)}>
7      <h3>{mission.name}</h3>
8      <p>Status: {mission.status}</p>
9    </div>
10  );
11});
12
13function MissionDashboard({ missions }) {
14  const [filter, setFilter] = useState('all');
15  const [selectedId, setSelectedId] = useState(null);
16
17  // You must remember to use useMemo...
18  const filteredMissions = useMemo(
19    () => missions.filter(m => filter === 'all' || m.status === filter),
20    [missions, filter]
21  );
22
23  // ...and useCallback for every function passed as a prop
24  const handleSelect = useCallback((id) => {
25    setSelectedId(id);
26  }, []);
27
28  return (
29    <div>
30      {filteredMissions.map(m => (
31        <MissionCard key={m.id} mission={m} onSelect={handleSelect} />
32      ))}
33    </div>
34  );
35}

Problems with manual memoization:

  • Easy to forget - miss a
    useCallback
    and
    React.memo
    won't work
  • Boilerplate - lots of code unrelated to business logic
  • Wrong dependencies - incorrect dependency array in
    useMemo
    /
    useCallback
    = bug
  • Over-memoization - memoizing things that don't need optimization

React Compiler - Automatic Memoization

React Compiler is a build-time tool that automatically analyzes React components and adds appropriate memoization. It works at compilation time -- your source code remains clean:

1// AFTER React Compiler - write plain, clean code
2function MissionDashboard({ missions }) {
3  const [filter, setFilter] = useState('all');
4  const [selectedId, setSelectedId] = useState(null);
5
6  // Compiler AUTOMATICALLY memoizes this computation
7  const filteredMissions = missions.filter(
8    m => filter === 'all' || m.status === filter
9  );
10
11  // Compiler AUTOMATICALLY stabilizes these functions
12  const handleSelect = (id) => {
13    setSelectedId(id);
14  };
15
16  return (
17    <div>
18      {filteredMissions.map(m => (
19        <MissionCard key={m.id} mission={m} onSelect={handleSelect} />
20      ))}
21    </div>
22  );
23}
24
25// You don't need React.memo - Compiler handles it!
26function MissionCard({ mission, onSelect }) {
27  return (
28    <div onClick={() => onSelect(mission.id)}>
29      <h3>{mission.name}</h3>
30      <p>Status: {mission.status}</p>
31    </div>
32  );
33}

How Does React Compiler Work?

The Compiler analyzes your code during the build (e.g., with a Babel plugin) and generates an optimized version:

1// Your source code (what you write):
2function StarList({ stars, highlight }) {
3  const visible = stars.filter(s => s.magnitude < 6);
4  const style = { color: highlight ? '#ffd700' : '#ccc' };
5
6  return (
7    <ul style={style}>
8      {visible.map(s => <li key={s.id}>{s.name}</li>)}
9    </ul>
10  );
11}
12
13// What the Compiler generates (simplified example):
14function StarList_compiled({ stars, highlight }) {
15  // Compiler adds cache for filtering
16  const visible = useMemo(
17    () => stars.filter(s => s.magnitude < 6),
18    [stars]
19  );
20
21  // Compiler caches the style object
22  const style = useMemo(
23    () => ({ color: highlight ? '#ffd700' : '#ccc' }),
24    [highlight]
25  );
26
27  return (
28    <ul style={style}>
29      {visible.map(s => <li key={s.id}>{s.name}</li>)}
30    </ul>
31  );
32}

The Compiler does this intelligently -- it does not memoize everything, only those parts that can actually repeat with the same data.

Configuring React Compiler

Installation with Babel

1// babel.config.js
2module.exports = {
3  plugins: [
4    ['babel-plugin-react-compiler', {
5      compilationMode: 'infer',
6      panicThreshold: 'NONE',
7    }],
8  ],
9};

Installation with Next.js

1// next.config.js
2module.exports = {
3  experimental: {
4    reactCompiler: true,
5  },
6};

Compilation Modes

  • infer
    (default) - Compiler decides which components to optimize
  • annotation
    - optimizes only components marked with the
    'use memo'
    directive
  • all
    - optimizes all components (most aggressive)

Rules of React

React Compiler works correctly ONLY if your code follows the "Rules of React":

1// GOOD - pure function, no side effects in render
2function GoodComponent({ data }) {
3  const sorted = [...data].sort((a, b) => a.name.localeCompare(b.name));
4  return <ul>{sorted.map(d => <li key={d.id}>{d.name}</li>)}</ul>;
5}
6
7// BAD - mutating props (Compiler may generate incorrect code!)
8function BadComponent({ data }) {
9  data.sort((a, b) => a.name.localeCompare(b.name)); // Mutation!
10  return <ul>{data.map(d => <li key={d.id}>{d.name}</li>)}</ul>;
11}
12
13// BAD - side effect in render
14function BadComponent2({ userId }) {
15  // Compiler will assume this is pure and may skip it!
16  analytics.track('render', userId);
17  return <div>User: {userId}</div>;
18}

Key rules:

  1. Components must be pure functions - same input = same output
  2. Do not mutate props or state directly
  3. Side effects only in
    useEffect
    , event handlers, or callbacks
  4. Do not read refs during rendering (only in effects and handlers)

ESLint Plugin

React Compiler requires following the rules. The ESLint plugin helps enforce them:

1// .eslintrc.js
2module.exports = {
3  plugins: ['react-compiler'],
4  rules: {
5    'react-compiler/react-compiler': 'error',
6  },
7};

Migrating Existing Code

If you have an existing project with manual memoization, you can gradually migrate. Existing

React.memo
and
useMemo
will not conflict with the Compiler -- they simply become an additional, unnecessary layer.

Summary

React Compiler is the future of React optimization:

  1. Automatic memoization - Compiler adds
    useMemo
    ,
    useCallback
    ,
    React.memo
    for you
  2. Cleaner code - you write simpler, easier to maintain code
  3. Fewer bugs - Compiler won't forget the dependency array
  4. Build-time - zero runtime cost, optimizations at compilation stage
  5. Requires clean code - components must follow the Rules of React

Remember: React Compiler is like an autopilot on a spaceship -- it does its job perfectly, but requires the ship to be properly built.

Go to CodeWorlds