React is React, just.
Part 2

2026年2月24日

注意: 筆者は Meta の関係者でも React Compiler の関係者でもありません.本記事はあくまで外部から観測できる情報に基づいた考察です.

前回の記事 では,React Compiler の登場によって React Component が「Just JavaScript」ではなくなったのではないか,という議論をした. 今回はその続きとして,Meta のエコシステム全体を俯瞰し,React が「言語」として進化していく様子をより深く考察する.

Meta と JavaScript インフラ

Meta (旧 Facebook) は JavaScript のエコシステムに対して長年にわたり大きな貢献をしてきた.

Babel

Babel は,もともと 6to5 という名前で始まった JavaScript のトランスパイラだ. ES6+ や JSX など,ブラウザがネイティブにサポートしていない構文を変換し,後方互換性を保つ役割を担っている.

JSX was created as an extension to ECMAScript with the purpose of designing a more concise and easy-to-understand syntax for building DOM tree structures and attributes. — The Role of Babel in React

Babel は独立したオープンソースプロジェクトだが,React のエコシステムにおいて不可欠な存在だ. そして,React Compiler も Babel Plugin として実装されている

Flow

Flow は Meta が開発している JavaScript の静的型チェッカーだ. Flow も Babel Plugin (@babel/preset-flow) として実装されており,型注釈や独自構文を実行時に削除する役割を担っている.

そして今日の主題の一つとして,Flow は型チェッカーを超えて「言語」としての拡張を行っている

Flow の Component Syntax と Hook Syntax

2024年4月,Flow チームは Component Syntax を発表した. これは React のプリミティブであるコンポーネントとフックに対する 一級言語サポート だ.

なぜ追加されたのか

Component Syntax was designed in coordination with the React team, and is already being used across Meta's codebases. — New Flow Language Features for React

These features bring improved ergonomics, expressiveness, and static enforcement for many of the Rules of React. — Flow Blog

つまり,Flow の Component Syntax は React チームと連携して設計 され,Rules of React を静的に強制する ことを目的としている.

Component Syntax の構文

通常の関数コンポーネントではなく,component キーワードを使って定義する:

// 従来の関数コンポーネント
function Introduction(props: { name: string, age: number }) {
  return <h1>My name is {props.name} and I am {props.age} years old</h1>
}

// Flow の Component Syntax
component Introduction(name: string, age: number) {
  return <h1>My name is {name} and I am {age} years old</h1>
}

参考: Component Syntax | Flow

Component Syntax では:

  • props が直接パラメータになる: ボイラープレートの削減
  • ref の自動処理: 内部で React.forwardRef でラップされる
  • 明示的な return が必須: すべてのブランチで return が必要
  • this の使用禁止: コンポーネント内で this は使えない

Hook Syntax の構文

同様に,hook キーワードを使ってフックを定義する:

// 従来のカスタムフック
function useOnlineStatus(initial: boolean): boolean {
  const [isOnline, setIsOnline] = useState(initial);
  // ...
  return isOnline;
}

// Flow の Hook Syntax
hook useOnlineStatus(initial: boolean): boolean {
  const [isOnline, setIsOnline] = useState(initial);
  // ...
  return isOnline;
}

参考: Hook Syntax | Flow

Flow が検出するもの

Flow の Component/Hook Syntax は,Rules of React に違反するコードを 静的に 検出する:

  1. Props の mutation 検出: コンポーネント内で props を変更しようとするコード
  2. 条件付きフック呼び出しの禁止: if 文内でのフック呼び出しをエラーとして報告
  3. レンダリング中の ref アクセス検出: レンダリング中に ref を読み書きするコード
  4. ネストした component/hook の検出: component や hook 内で別の component/hook を定義するコード

Flow is able to detect mutations of props in a component or hook. Another pattern enforced in component bodies is that refs are not read or written to during render. — Flow Documentation

これが意味すること

Flow の Component Syntax と Hook Syntax は,React を「言語」として明示的に定義する試み だ.

従来,React コンポーネントは「JavaScript の関数」として定義されていた. しかし,Flow は新しいキーワード (component, hook) を導入することで,React のセマンティクスを言語レベルで表現 している.

これは前回の記事で議論した「React は React だ」という結論を,より明確な形で示している.

React Compiler: 暗黙的なアプローチ

Flow が「明示的」に新しい構文を導入しているのに対し,React Compiler は「暗黙的」なアプローチを取っている.

React Compiler の歴史

React Compiler は約 10年 にわたる研究の成果だ:

  • 2017年: Facebook が Prepack でコンパイラを初めて探索
  • 2021年: Xuan Huang が新しいアプローチの最初のイテレーションをデモ
  • 2024年: ベータ版リリース,React Conf 2024 で発表
  • 2025年10月: React Compiler v1.0 安定版リリース

参考: React Compiler v1.0 – React

Hooks: React を「言語」として定義した瞬間

ここで一つの重要な視点を提示したい.

React を「言語」として定義したのは Hooks の登場時点だった.

Hooks には Rules of Hooks という,JavaScript には存在しない制約がある:

  • トップレベルでのみ呼び出す (ループ,条件分岐,ネストした関数内では呼ばない)
  • React 関数からのみ呼び出す (通常の JavaScript 関数からは呼ばない)

これらは JavaScript の関数には存在しないルールだ. Hooks を使う関数は,もはや「JavaScript の関数」ではなく 「React の関数」 になる.

つまり,Hooks の導入こそが,React を独自のセマンティクスを持つ「言語」として定義した瞬間だった と言えるかもしれない.

Hooks の設計とコンパイラ

そして,Hooks は最初からコンパイラによる最適化を前提として設計されていた.

React Compiler v1.0 のブログには以下の記述がある:

Hooks の設計自体がコンパイラの将来を見据えて設計されました. — React Compiler v1.0

これは後付けの話ではない.2018年に公開された Hooks の公式ドキュメント には,既にこの意図が明記されていた:

As Svelte, Angular, Glimmer, and others show, ahead-of-time compilation of components has a lot of future potential. Especially if it's not limited to templates.

Introducing Hooks – React (2018)

We wanted to present an API that makes it more likely for code to stay on the optimizable path. To solve these problems, Hooks let you use more of React's features without classes.

Introducing Hooks – React (2018)

つまり,Hooks は最初からコンパイラによる最適化を前提として設計されていた

Dan Abramov の発言

当時 React チームにいた Dan Abramov も,コンパイラによる自動メモ化について早い段階から言及していた.

2021年2月に公開された記事 "Before You memo()" では,手動でのメモ化の手間について触れた上で,以下のように述べている:

This last step is annoying, especially for components in between, and ideally a compiler would do it for you. In the future, it might.

— Dan Abramov, Before You memo() (2021)

「将来的には,コンパイラがこれを自動で行うかもしれない」——この発言は React Compiler が一般公開される 3年以上前 のものだ.

React チームは長年にわたり,コンパイラによる自動最適化 という明確なビジョンを持っていた. これは,React が「Just JavaScript」から「独自のセマンティクスを持つ言語」へと進化していく過程が,計画的なものであったことを示している.

React Compiler が行うこと

前回の記事でも触れたが,React Compiler は以下のような最適化を自動で行う:

// 入力
function VideoTag({ heading, videos, filter }) {
  const filteredVideos = [];
  for (const video of videos) {
    if (applyFilter(video, filter)) {
      filteredVideos.push(video);
    }
  }
  // ...
}
// 出力 (コンパイル後)
function VideoTab(t36) {
  const $ = useMemoCache(12);
  const { heading, videos, filter } = t36;
  let filteredVideos;

  if ($[0] !== videos || $[1] !== filter) {
    filteredVideos = [];
    for (const video of videos) {
      if (applyFilter(video, filter)) {
        filteredVideos.push(video);
      }
    }
    $[0] = videos;
    $[1] = filter;
    $[2] = filteredVideos;
  } else {
    filteredVideos = $[2];
  }
  // ...
}

参考: Understanding Idiomatic React – Joe Savona, Mofei Zhang, React Advanced 2023

条件付きメモ化: useMemo では不可能なこと

React Compiler v1.0 のブログでは,手動の useMemo/useCallback では実現できない最適化 の例が示されている:

export default function ThemeProvider(props) {
  if (!props.children) {
    return null;
  }
  // コンパイラは条件付きリターン後のコードもメモ化できる
  // (手動の useMemo/useCallback では不可能)
  const theme = mergeTheme(props.theme, use(ThemeContext));
  return (
    <ThemeContext value={theme}>
      {props.children}
    </ThemeContext>
  );
}

これは useMemo/useCallback では実装できない,コンパイラ固有の能力です. — React Compiler v1.0

Rules of React の静的強制

React Compiler には Rules of React を検証するパス が含まれており,ESLint プラグインを通じて診断が提供される:

React Compiler's ESLint plugin helps developers proactively identify and correct Rules of React violations. The team strongly recommends everyone use the linter today. — React Compiler Beta Release

Meta での成果

React Compiler は既に Meta の本番環境で運用されている:

  • Instagram: 全ページで平均 3% 改善
  • Quest Store: ロード時間が少なくとも 4% 改善,一部のインタラクションは 2倍以上 高速化,初期ロードは最大 12% 改善

参考: React Compiler v1.0

React Compiler と Flow の連携

ここで重要なのは,React Compiler は Flow の Component/Hook Syntax を明示的にサポートしている ということだ.

compilationMode オプション

React Compiler には compilationMode というオプションがあり,どの関数をコンパイル対象とするかを制御できる:

  • 'infer' (デフォルト): コンポーネント命名規則 (PascalCase) とフック検出 (use プレフィックス) を使用
  • 'annotation': "use memo" ディレクティブでマークされた関数のみ
  • 'syntax': Flow の component/hook 構文を使用した関数のみ
  • 'all': すべてのトップレベル関数 (非推奨)

'syntax' モード

'syntax' モードを使用すると,Flow の専用構文で定義されたコンポーネントとフックのみがコンパイル対象となる:

// babel.config.js
{
  compilationMode: 'syntax'
}
// ✅ コンパイル対象:Flow component 構文
component Button(label: string) {
  return <button>{label}</button>;
}

// ✅ コンパイル対象:Flow hook 構文
hook useCounter(initial: number) {
  const [count, setCount] = useState(initial);
  return [count, setCount];
}

// ❌ コンパイル対象外:通常の関数構文
function helper(data) {
  return process(data);
}

参考: compilationMode – React

これが意味すること

Flow と React Compiler は 別々のプロジェクトではなく,連携して設計されている

  • Flow の Component Syntax は React チームと連携して設計された
  • React Compiler は Flow の構文を明示的にサポートしている
  • Meta の内部では,この二つが組み合わせて使用されている

つまり,Meta は「React を言語として定義する」という一貫した戦略のもとで,Flow と React Compiler の両方を開発している.

React ドキュメントと function キーワード

ここで一つの観察を共有したい.

React の公式ドキュメント では,コンポーネントの定義に 一貫して function キーワード が使われている:

export default function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3Am.jpg"
      alt="Katherine Johnson"
    />
  )
}

参考: Your First Component – React

アロー関数 (const Profile = () => {}) についての言及は 一切ない

なぜアロー関数ではないのか

Dan Abramov は overreacted.io で以下のように述べている:

it doesn't matter whether I use arrows or function declarations — Dan Abramov

技術的には,アロー関数でも関数宣言でも React コンポーネントとして問題なく動作する. しかし,React ドキュメントが function キーワードを使い続けていることには,いくつかの考察ができる.

1. Flow の Component Syntax との親和性

Flow の Component Syntax は component キーワードを使う:

component Introduction(name: string, age: number) {
  // ...
}

これは function キーワードを置き換える形で自然に導入できる. もし React ドキュメントがアロー関数を推奨していたら,この移行は不自然になる.

2. 構文の一貫性

function キーワードによる宣言は,将来的に専用構文 (Flow の Component Syntax のようなもの) へ移行する場合にも自然な形で置き換えられる. アロー関数からの移行よりも,関数宣言からの移行の方が構文的に一貫性がある.

二つのアプローチの対比

Flow と React Compiler は,同じ問題に対して異なるアプローチを取っている:

Flow:

  • 方法: 新しいキーワード (component, hook)
  • 明示性: 明示的 (新構文)
  • 対象: Meta の内部コードベース
  • 目的: Rules of React の静的強制

React Compiler:

  • 方法: 既存の構文を変換
  • 明示性: 暗黙的 (変換)
  • 対象: 全 React ユーザー
  • 目的: 自動メモ化 + Rules of React の検証

しかし,どちらも「React は独自のセマンティクスを持つ」という方向性では一致している

Rules of React

ここで改めて Rules of React を確認しておこう:

Rules は,アイディオマティック(慣用的)で高品質な React コードを書くためのルールです.単なるガイドラインではなく,これに従わないとバグが生じます. — Rules of React – React

主要なルール:

  1. Components と Hooks は Pure(純粋)である必要がある

    • 冪等性: 同じ入力に対して常に同じ出力
    • Side Effects はレンダリングの外側でのみ実行
    • props, state, Hook の戻り値は不変
  2. React が Components と Hooks を呼び出す

    • コンポーネント関数を直接呼ばない
    • Hook を通常の値として渡さない
  3. Rules of Hooks

    • トップレベルでのみ呼び出す
    • React 関数からのみ呼び出す

これらのルールは「React 的意味論」を形成している. そして,Flow の Component Syntax も React Compiler も,これらのルールを 静的に強制する ことを目指している.

結論: React は「言語」として進化している

前回の記事で私は以下のように結論した:

React は,React だ. 構文が JavaScript と同じで,意味が異なる別の存在だ.

今回の調査で,この結論はさらに強化された:

  1. Flow の Component Syntax は,React のセマンティクスを 明示的に言語として定義 している
  2. React Compiler は,React のセマンティクスを 暗黙的に JavaScript に変換 している
  3. Hooks は最初からコンパイラを前提として設計されていた
  4. React ドキュメントは function キーワードを一貫して使用 しており,将来の構文拡張に備えている可能性がある

React が「Just JavaScript」であった時代は,徐々に終わりを迎えつつある. React は React だ ——この言葉の意味は,今後ますます重要になっていくだろう.


これは私の単なるエッセイであり,React Team や Meta の公式見解ではありません.

関連コンテンツ

記事一覧に戻る