⚛️ React Boundary
内部理解 — アーキテクチャ

Reactのレンダリングフェーズ

Reactは「レンダリング」を一度に行わない。render phaseとcommit phaseに分け、それぞれ異なる目的で実行します。

🎯 結論

Reactのレンダリングは2フェーズに分かれています:

① render phase — 「何を変えるか」を計算する(純粋な計算)

② commit phase — 「実際にDOMを変える」(副作用を伴う実行)

この分離がReactのConcurrent Modeを可能にし、UIの応答性を保つ基盤になっています。

📐 2つのフェーズの全体像

Reactのレンダリングパイプライン
① Render Phase(純粋な計算)
→ コンポーネント関数を実行
→ 新しいFiberツリーを構築
→ 前回のツリーとdiff(Reconciliation)
→ 「変更すべき差分リスト」を作成
⚡ 中断・一時停止・再実行が可能
↓ 差分リスト確定
② Commit Phase(実際の反映)
→ DOMを実際に操作(挿入・更新・削除)
→ refを更新
→ useLayoutEffect を同期実行
→ useEffect をスケジュール(非同期)
🔒 中断不可能(DOMとの整合性を保つ)

🔵 Render Phase:純粋な計算

render phaseでは、Reactはコンポーネント関数を実行して新しいVirtual DOMツリー(Fiberツリー)を構築し、 前回のツリーと比較してどこが変わったかを計算します。

重要:render phaseでDOMは変わらない

render phaseは完全に「計算だけ」です。実際のDOMには一切触れません。 だからこそ、Concurrent Modeではこのフェーズを途中で中断して、より優先度の高いタスク(ユーザー入力など)を先に処理できます。

// render phaseではこういう処理が起きている
function performUnitOfWork(fiber) {
  // コンポーネント関数の実行(例: () => <div>...</div>)
  const newChildren = fiber.type(fiber.props);
  
  // 子要素のFiberを作成 & 前回との差分を記録
  reconcileChildren(fiber, newChildren);
  
  // 次に処理するFiberを返す(中断可能)
  return fiber.child || fiber.sibling;
}

🟢 Commit Phase:副作用の実行

commit phaseでは、render phaseで作成した「差分リスト」を使って実際のDOMを更新します。 このフェーズは同期的・中断不可能で実行されます。

commit phaseの3段階

1
Before Mutation
getSnapshotBeforeUpdate / useLayoutEffect クリーンアップ
2
Mutation
実際のDOM操作(insertBefore, removeChild, textContent更新など)
3
Layout
useLayoutEffect の実行(DOM更新直後・ブラウザ描画前)

useEffect vs useLayoutEffect

useLayoutEffectはcommit phase内(ブラウザ描画前)に同期実行されます。 一方useEffectはcommit phase完了後、ブラウザが描画した後に非同期で実行されます。 DOM計測が必要な場合はuseLayoutEffect、通常の副作用はuseEffectを使います。

⚡ なぜ分けることが重要なのか?

render phaseとcommit phaseを分けることで、ReactはConcurrent Modeを実現できます。

旧モデル レンダリング = DOMを変える。中断できない。大きな更新でUIがフリーズする可能性。
新モデル render phase(計算)は中断可能。ユーザー入力など高優先度の更新を先に処理できる。commit phaseだけDOMを変える。
// Concurrent Modeのイメージ
[render phase - ユーザーリスト更新中...]
  → ユーザーがキーを入力!(高優先度)
  → 現在のrender phaseを中断
  → 入力のrender phaseを先に実行・commit
  → 元のrender phaseを再開・commit

📌 まとめ

  • ✓ render phase:コンポーネントを実行して差分を計算する(DOMは変えない)
  • ✓ commit phase:実際のDOMを変える(中断不可・同期的)
  • ✓ render phaseが中断可能なことがConcurrent Modeの基盤
  • ✓ useLayoutEffectはcommit phase内(ブラウザ描画前)、useEffectはその後(非同期)

関連記事