メインコンテンツへスキップ

React の公開モデルはしばしば UI = f(state) と要約されます。与えられた state に対して UI がどうあるべきかを記述し、state が変わると React が rendered output をどう更新するか決めます。

render を「React が component を呼んで DOM を更新する」と考えるのをやめたとき、React は reasoning しやすくなりました。その説明は、event handler の stale state、list items 間の state 移動、開発時 Effect の二重実行、transition の途中放棄など、多くの意外な挙動を説明する機構を飛ばします。

より有用なモデルは、React が UI の独自表現を保持することです。update が scheduled され、React は render phase で possible next tree を計算し、commit phase でだけ結果を公開します。


event, promise, or external store
  → enqueue an update
  → assign a priority
  → render and reconcile a possible next tree
  → commit the finished changes
  → let the browser paint

この記事は JSX から pixels までその経路を辿ります。render purity、state snapshots、type と key による identity、render/commit 分割などは React の公開 mental model の一部です。FiberlanesbeginWork、effect flags といった名称は React 19.2 の実装を述べます。React 理解に有用ですが、アプリケーションコードは依存すべきではありません。



1. JSX は DOM Nodes ではなく Description を生む

JSX は UI を記述する syntax です。現代の JSX transform は次を:


function Greeting({ name }: { name: string }) {
  return <h1 className="greeting">Hello, {name}</h1>
}

JSX runtime 呼び出しに変え、React element を作ります。概念的には結果は次に似ます:


{
  type: "h1",
  key: null,
  props: {
    className: "greeting",
    children: ["Hello, ", name],
  },
}

この object は description であり、<h1> element でも Fiber でもありません。React がこの render を commit すれば何があるべきか、と述べています。

Component element の type は function か class です:


const element = <Greeting name="Ada" />

React は後で rendering 中に Greeting を呼び、返された elements で description 構築を続けます。component を直接呼ぶ——Greeting({ name: "Ada" })——は React の component identity と Hook bookkeeping を bypass するため、components は JSX に現れるべきです。

React elements は安価で immutable な snapshots です。一つ作っても mount、Effect 実行、DOM 操作は起きません。React は commit されない render のために多くの elements を作り検査し得ます。

したがって三つの tree を分けて考える価値があります:


React elements   declarative descriptions returned by components
Fiber tree       React's persistent bookkeeping and unit-of-work tree
Host tree        DOM nodes, native views, or another renderer's output

Host tree は renderer 依存です。react-dom は DOM nodes、React Native は native views、React Three Fiber は Three.js scene graph を作ります。React 自体は renderer 非依存——element と Fiber 層はすべての target で同じです。

これらを混同すると誤った前提になります。新しい element object が必ず新しい DOM node を意味せず、component render が必ず可視ブラウザ更新を意味しません。



2. Fiber は React の Unit of Work

React は elements が一時的 description なので state や scheduling 情報を element objects に置けません。render から render へ生き残る persistent structure が必要です。現行 renderer ではそれが Fiber tree です。

Fiber は React tree 内の component、host element、text node、Suspense boundary など一 unit に対応します。Fiber は他にも次を記録します:

  • component か host の typekey
  • 進行中 render の pendingProps
  • 完了 work の memoizedPropsmemoizedState
  • parent、first child、next sibling へのリンク
  • もう一方 tree の対応 Fiber を指す alternate
  • update queue と context dependencies
  • pending priorities を表す lanes
  • commit 時に必要な work を述べる flags
  • host Fiber なら対応 DOM node などの stateNode

React は常にこうではありませんでした。React 16 以前、reconciliation は component tree の再帰走査——"stack reconciler"——として一度に走りました。rendering が始まると、一般に traverse 完了まで止められませんでした。

その設計は大きな updates で問題を作りました。高コスト render が input handling をブロックし paint を遅らせ、React は rendering を pause できず、obsolete work をきれいに abandon しにくく、urgent updates を non-urgent より優先する能力も限られていました。

React 16 の Fiber は traverse state を JavaScript call stack から明示的 heap-allocated objects へ移しました。各 Fiber は component か host element の virtual stack frame のように働きます。

Fibers はネストした JavaScript array ではなく childsiblingreturn リンクを使います:


App
  child → Header
            sibling → Main
                        child → Article

Article.return → Main
Main.return    → App

この形により React は tree を一 unit ずつ歩き、units 間で pause し、後で resume できます。

update では React は通常、関連する Fiber の二バージョンを扱います。current Fiber は画面上の tree に属します。その alternatework-in-progress Fiber を指し、React が candidate next state を計算します。work-in-progress Fiber は current へ戻ります。


current tree                         work-in-progress tree

App ───────────── alternate ───────────── App
 └─ List ──────── alternate ──────────── List
     └─ Item ──── alternate ──────────── Item

React は private work-in-progress objects を mutate しつつ current tree と DOM を安定に保てます。より高 priority work が来るか rendering が失敗すれば attempt を abandon できます。render 完了なら finished work-in-progress tree が commit 時に current になります。

これは double buffering と呼ばれ、offscreen に frame を描いてから提示するのに似ています。React が毎回アプリ全体を最初から clone する意味ではありません。Fibers と subtrees は再利用でき、inputs と pending work が許せば bail out できます。



3. State Setter は Work を Schedule する

state setter を呼んでも、実行中 function が捕捉した state 変数は mutate されません。update を作り、React に再 render を依頼します。


function Counter() {
  const [count, setCount] = useState(0)

  function increment() {
    setCount(count + 1)
    console.log(count) // Still 0 in this event handler
  }

  return <button onClick={increment}>{count}</button>
}

count binding は Counter の一回の呼び出しに属します。event handler はその render の値を閉じ込めます。React は実行中の JavaScript binding を書き換えられません。代わりに setCount は未来 render 用の値を queue します。

内部では state update に action と lane などが含まれます。React は Hook の update queue に append し、その Fiber から root まで work を mark し、root を schedule します。正確な構造は実装詳細ですが、観測モデルは安定しています:


current state snapshot + queued updates → next state snapshot

複数 updates が前結果に依存するとき updater functions が重要な理由です:


function addThree() {
  setCount((value) => value + 1)
  setCount((value) => value + 1)
  setCount((value) => value + 1)
}

次 render 中、React は queue 順に functions を処理し、各結果を次へ渡します。count0 なら next state は 3 です。

対照的に setCount(count + 1) を三回呼ぶと、同じ count を捕捉し、すべて replacement 値 1 を要求します。+1 の連鎖にはなりません。

React は batch して、関連 setter 群の後に一度 render し、半完成 states を露出させません。batching はすべての update を一値に merge する意味ではありません。各 queued update は next state 計算に参加します。適切な boundary まで処理を遅らせる、という意味です。

場合によって React は Hook update を eagerly 計算し、Object.is で next value が current と等しければ scheduling を skip できます。それは最適化であり、アプリ logic を組み立てる保証ではありません。React が bail out して見えても components と updater functions は pure である必要があります。



4. Lanes は Priority を表す

すべての update が同じくらい urgent ではありません。input への typing は即応すべき、大きな検索結果 refresh は待て、hidden work はさらに待てます。

React 19.2 は lanes でこれら priorities を表します。lane は bitmask の bit で、lane 集合は複数 pending work クラスを同時に述べられます。Scheduler は lower-priority updates を消さず highest-priority pending lanes を選べます。


urgent input update       ─┐
default data update        ├─ pending lanes on the root
transition update          ┤
retry for Suspense        ─┘

update は source と context に基づき lane を受け取ります。React は Fiber tree へ root まで lane を propagate し、render する lanes を選び、skip した updates は後の pass 用 queue に残します。

priority は「どの callback が先に走るか」以上の意味があります。React は transition rendering を始め、urgent input update を受け、transition attempt を pause か discard し、urgent 結果を commit し、最新 tree に対して transition を restart し得ます。

startTransition は state updates を non-urgent に mark します:


const [query, setQuery] = useState("")
const [filter, setFilter] = useState("")
const [isPending, startTransition] = useTransition()

function handleChange(value: string) {
  setQuery(value)

  startTransition(() => {
    setFilter(value)
  })
}

input state は urgent に更新でき、filter ベースの高コスト結果は background render できます。Transition は JavaScript を別 thread に移さず、高コスト計算を無料にせず、startTransition に渡した function を遅らせません。その function 内で synchronously scheduled された React updates に transition priority を付けます。

lanes の名前と数は React バージョンで変わり得ます。 durable な教訓は、React が どの work が pending か今どれを試すべきか を別々に追うことです。



5. Render Phase は Candidate Tree を計算する

root が選ばれた lanes で work を持つと React は render phase に入ります。Rendering は「これら updates を適用すれば tree はどう見えるか?」に答えます。

高レベルでは Fiber work loop は depth-first traversal です:


beginWork(parent)
  → beginWork(first child)
    → beginWork(grandchild)
    → completeWork(grandchild)
  → completeWork(first child)
→ completeWork(parent)

beginWork は Fiber inputs を処理し children を決めます。function component では React が component を呼び Hooks を実行する場所です。返された children を current children と reconcile します。

completeWork は descendants 完了後に走ります。host components では DOM instances を作るか準備します。subtree flags などを root へ bubble し、commit phase が effects のない branch を skip できます。

render phase は pure である必要があります。speculative だからです。concurrent rendering では React は browser に yield し、新 inputs で restart し、component を複数回 render し、commit せず結果を捨てられます。

これは unsafe です:


let nextId = 0

function Row() {
  nextId += 1
  return <li>Row {nextId}</li>
}

可視 IDs は React が Row を呼んだ回数——開発チェックや abandoned renders 含む——に依存します。

Rendering は props、state、context、immutable 外部 snapshots を読めます。elements を計算して返せます。analytics 送信、共有 object の mutate、service 購読、DOM 直接編集はしてはいけません。それらは起きたことを述べ、render は possible future だけを述べます。



6. Reconciliation は Identity を決める

Rendering 中、React は新 child elements を既存 child Fibers と照合します。一般 tree-diff は高コスト——任意 tree に対する既知の最良アルゴリズムは n elements で O(n³)——なので React は主に typepositionkey に基づく実用ルールを使い、common UI updates をおおよそ線形時間で扱います。

同じ位置の child では:

  • 同じ type と compatible key:Fiber を reuse し state を保持。
  • 異なる type:旧 subtree を除去し新しいものを mount。
  • 異なる key:type が同じでも別 identity として扱う。

例:


function Profile({ editing }: { editing: boolean }) {
  return editing ? <Editor /> : <Preview />
}

EditorPreview は同位置だが type が異なるため、モード切替で subtree state が reset されます。

key で意図的に state を reset できます:


<Editor key={documentId} documentId={documentId} />

documentId 変更で React は新 identity を見て Editor subtree を再作成します。local state を手動 clear する Effect よりきれいなことが多いです。

Arrays では keys が insertions、removals、moves 間で siblings を照合します:


{
  todos.map((todo) => <TodoRow key={todo.id} todo={todo} />)
}

keys は siblings 間で unique ならよく、通常 prop としては渡りません。array index は item identity が本当に position に従うときだけ安全です。reorder で index 0 の所有者が変わると、React は index 0 の component state を保持し、誤った data に付け替え得ます。

微妙な点:state は「component function の内側」には住みません。React は parent tree の特定位置の Fiber identity に state を関連付けます。component functions は再び呼ばれます。React は対応 Fiber が同じ概念的 component かで state を保持か reset します。



7. Commit Phase は結果を公開する

React が render を完了すると finished Fiber tree と必要変更を述べる flags 集合を持ち、commit phase に入ります。

concurrent rendering と異なり、root に対する committing は同期的です。finished tree の公開を始めたら、半分は今回 commit、半分は別 commit、とはなりません。

簡略 commit 順序:


before-mutation work
  → DOM mutations and deletions
  → current tree switches to the finished tree
  → refs and layout effects
  → browser gets an opportunity to paint
  → passive effects

正確な内部 functions はより細かいですが、この順序が公開 API を説明します:

  • getSnapshotBeforeUpdate は mutations 直前に host 情報を読む。
  • React は mutation work 中に host nodes を insert、update、remove。
  • Ref callbacks と useLayoutEffect は browser が通常 paint する前に committed DOM を観測。
  • useEffect は passive で通常 paint 後。一部 interaction-driven updates では React が早く flush し得る。

Layout work は paint をブロックするため、ユーザーが frame を見る前に必要な measurement か visual correction 用に留めるべきです:


useLayoutEffect(() => {
  const rectangle = tooltipRef.current?.getBoundingClientRect()
  setTooltipHeight(rectangle?.height ?? 0)
}, [])

大半の synchronization は browser を先に paint させるため useEffect に属します。

Effect cleanup も committing の一部です。dependencies 変更で Effect を再実行する前に前 cleanup を走らせ、unmount では最終 cleanup です。各 Effect は独立 synchronization プロセスになります:


useEffect(() => {
  const connection = connect(roomId)
  connection.open()

  return () => connection.close()
}, [roomId])

DOM 変更と pixels 表示は同じイベントではありません。React は JavaScript が main thread を占有中に DOM を mutate します。browser はその work が yield した後 style、layout、paint できます。長い layout Effect は DOM 更新済み commit の paint を遅らせ得ます。



8. Hooks は Fiber 上の Positional State

Hooks は普通の function calls に見えますが state は React が保持し、ローカル JavaScript 変数ではありません。React 19.2 では function component Fiber が Hooks を memoizedState 上の linked list として持ちます。

概念的に:


Profile fiber
  memoizedState
    → useState hook
    → useReducer hook
    → useEffect hook
    → null

次 render 中、Hook dispatcher は旧と work-in-progress Hook lists を呼び出し順に歩きます。最初の useState が最初の state cell、二番目 Hook が二番目 cell、と続きます。

Hooks を条件付きで呼べない機械的理由です:


function Profile({ editable }: { editable: boolean }) {
  const [name, setName] = useState("")

  if (editable) {
    useEffect(() => subscribeToDraft(name), [name]) // Incorrect
  }

  const [saved, setSaved] = useState(false)
  // ...
}

editable が変わると条件以降の Hook がずれます。React は呼び出しと正しい state cells を対応付けられません。「Hooks は top level だけ」は sequence を保つためです。

条件は Hook 内に置きます:


useEffect(() => {
  if (!editable) return
  return subscribeToDraft(name)
}, [editable, name])

毎 render 同じ Hook sequence になり、条件 logic は Effect が何をするかだけ決めます。

各 state Hook は update queue も持ちます。Rendering 中 React は base state と現在 render に含まれる lanes の updates を合わせます。lower-priority updates は base queue に残り後で replay できます。urgent render が transition updates を失わず進めます。

Closures がモデルを完成させます。毎 render 新 event handlers と Effect setup functions がその render の props と state を捕捉します。「Stale closure」は React が古い変数を返すのではなく、古い render の code が後で走ることです。

Dependencies は Effect synchronization inputs が変わったタイミングを React に伝えます。reactive dependency を省略しても最新値に freeze するわけではなく、古い closure を保持します:


useEffect(() => {
  const id = setInterval(() => {
    console.log(count)
  }, 1000)

  return () => clearInterval(id)
}, []) // This closure keeps the initial count.

正しい fix は意図次第:count を含める、functional state updater、interaction logic を event handler へ、Effect から呼ぶ non-reactive logic に Effect Event。dependency rule を無効化しても closure 意味論は変わらず、不一致を隠すだけです。



9. Bailouts と Memoization は Work を Skip するが Meaning は Skip しない

React は毎 update で全 component を呼ぶ必要はありません。関連 props、state、context、lanes が現在 priority で自分も descendants も work 不要と示せば Fiber は bail out できます。

memo は component boundary で props 比較を追加します。useMemo は dependencies が等しい間 committed renders 間で計算を cache します。useCallback は function reference で同様です。

これらは性能ツールであり semantic 保証ではありません:


const visibleTodos = useMemo(
  () => expensiveFilter(todos, filter),
  [todos, filter]
)

React が再計算しても計算は正しい必要があります。再 render しても component は正しい必要があります。Memoization は impure render を安全にしません。

parent だけ render し child はしない、component は render するが DOM は変わらない、もあり得ます。Rendering は React が description を求めたこと。host mutation commit は reconciliation が host tree に届ける差分を見つけたときだけです。

性能調査では三問を分けます:

  1. update は scheduled されたか?
  2. どの components が render work をしたか?
  3. どの host changes と Effects が committed されたか?

三者をすべて「re-render」と見なすと profiles と logs が解釈しにくくなります。



10. Suspense は Waiting を Render Control Flow にする

Suspense は render が tree の一部が未 ready だと言えます。React 19 では use が Promise を読めます:


function UserProfile({
  userPromise,
}: {
  userPromise: Promise<{ name: string }>
}) {
  const user = use(userPromise)
  return <h2>{user.name}</h2>
}

function Page({ userPromise }: { userPromise: Promise<{ name: string }> }) {
  return (
    <Suspense fallback={<p>Loading profile...</p>}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  )
}

Promise が pending なら React はその rendering path を suspend し、最も近い Suspense boundary を見つけ fallback を render できます。React は pending resource を追い、settle で retry を schedule します。


render UserProfile
  → resource is pending
  → mark nearest Suspense boundary
  → render or preserve fallback/content
  → Promise settles
  → schedule retry
  → render UserProfile again

Suspense 自体は fetch しません。framework か cache が stable Promise を供給し lifetime を調整する必要があります。client render ごとに fresh Promise を作ると、毎 render 新 resource を見て繰り返し suspend します。

Transitions は Suspense が何を reveal するかに影響します。non-urgent navigation では React は既に visible な content を保ちつつ次 state を準備でき、すぐ fallback で置き換えません。transition が interrupt されても current committed tree は使えます。

Fiber の current/work-in-progress 分割から直接続きます:waiting は candidate tree に属し、committed tree は別 render 未完了だけで消える必要はありません。



11. Hydration は Server HTML を Reuse する

Server rendering は HTML を生みますが HTML だけに React state、event handling、client Fiber tree はありません。Hydration は client 表現を構築しつつ既存 host nodes と照合します。


server
  React tree → HTML stream → browser displays content

client
  load JavaScript
    → create root work
    → match Fibers to existing DOM
    → attach event behavior
    → continue as an interactive React tree

Hydration は単に「event listeners を足す」ではありません。React は component output を歩き、state と context を再構築し、Fibers を host nodes に関連付け、client が compatible markup を期待することを検証します。

Mismatch は server と client が同じ initial tree に異なる description を生んだことです:


function Clock() {
  return <time>{new Date().toLocaleTimeString()}</time>
}

server 時刻と hydration 時刻は異なり得ます。browser-only branch、random values、変化する外部 data、locale 差、無効 HTML nesting も同様です。

fix は initial render を deterministic にし、server snapshot を client に渡すか、hydration 後に意図的に client-only 情報を render することです。suppressHydrationWarning は既知の一レベル text か attribute mismatch 用 escape hatch で、一般 repair 機構ではありません。

Suspense boundaries も streaming と hydration を section 単位で調整できます。server は全 content ready 前に shell を送り、client は user interaction 周りで hydration を優先できます。frameworks は高レベルで多くを公開しますが、目標は同じ:ページ全体を all-or-nothing render 待ちにしないことです。



12. Strict Mode は Restartable Code をテストする

開発では Strict Mode が意図的に extra work をします。render functions を二回呼び、Effects に追加 setup-and-cleanup、ref callbacks を再実行。production では同じようには起きません。

React が「二回 render する」と言われがちですが、目的はより具体的:rendering が restart されるか synchronization が remount されると壊れる code を見つけることです。

Impure render は自ら露呈します:


function StoryTray({ stories }: { stories: string[] }) {
  stories.push("Create Story") // Mutates the prop during render.
  return stories.map((story) => <div key={story}>{story}</div>)
}

extra render が二回追加し mutation を露呈します。正しい component は新 array を作ります:


function StoryTray({ stories }: { stories: string[] }) {
  const items = [...stories, "Create Story"]
  return items.map((story) => <div key={story}>{story}</div>)
}

cleanup なし Effect も duplicate subscriptions を露呈します。fix は二回目 setup を抑える ref ではありません。setup → cleanup → setup が一回の real setup と等価になる cleanup です。

Strict Mode は concurrent rendering、navigation、state preservation、将来 React 機能が exercise しうる前提の preview です。render 中 pure、Effect cleanup 中対称な code は speculative attempt が何回あっても気にする必要がありません。



13. 一つの Update を End to End で追う

ユーザーが検索欄に type し、アプリが input を urgent 更新しつつ transition で大きな list を filter すると仮定します。

完全な path:

  1. ブラウザが React event system 経由で input event を dispatch。
  2. Handler が setQuery を呼び urgent Hook update を作る。
  3. Handler が startTransition を呼び setFilter が transition update を作る。
  4. 両 updates が queued され lanes が root へ propagate され root が scheduled。
  5. React が urgent work を先に選び work-in-progress Fibers を作るか reuse。
  6. beginWork 中、inputs か lanes が work を要する components を呼び relevant Hook queues を処理。
  7. Reconciliation が返された elements を type、key、position で current child Fibers と照合。
  8. completeWork が host changes を準備し effect flags を bubble。
  9. React が urgent 結果を同期的 commit し input DOM と layout work を更新。
  10. ブラウザが最新 input 値を paint できる。
  11. React が transition lanes を試す。render は Fiber units 間で yield 可能。
  12. 別 keystroke が来れば attempt を abandon か pause し newer urgent input を commit。
  13. transition render が supersede されず完了すれば filtered list を commit。
  14. committed work に関連する passive Effects が scheduling に従って実行。

どの時点でも React は古い handler 内の query binding を mutate しません。新 snapshots で新 renders を作ります。部分完了 transition が DOM に漏れることもありません。完了 commit だけが visible host tree を変えます。

この lifecycle が state snapshots、queues、lanes、Fiber traversal、reconciliation、atomic commits、concurrent rendering を結びます。



14. 私が使う Debugging Questions

React の挙動に驚いたら、次の問いを順に辿ります:

  1. どの render がこの callback を作ったか? closure にはその render の props と state がある。
  2. setter は replacement か updater か? 繰り返し replacement は一 snapshot を使いうる。
  3. この component の identity は? parent position、type、key を確認。
  4. この code は render 中か commit 中か? render は pure。外部 sync は Effect か event。
  5. React は render、commit、両方か? component の console logs は DOM 変更を証明しない。
  6. work は restart されうたか? Strict Mode と concurrent rendering が restartability を可視化。
  7. Effect は外部 system と sync しているか? でなければ値は render か event handler に属するかも。
  8. reactive Effect dependencies はすべて宣言したか? でなければ古い closure が reuse されている可能性。
  9. この update は urgent か transitional か? priority はいつ試すかに影響し、結果正しさには影響しない。
  10. server 初回 output と client 初回 output は同一か? でなければ hydration は安全に match できない。

症状が消えるまで memo、key 変更、lint 抑制、Effect 移動よりこれらの問いの方が信頼できます。



15. よくある誤解

Fiber について十分よく出る考えを直接訂正します。

「Fiber は virtual DOM だ」 — 厳密には違います。第 1 節の三 tree のとおり、elements は declarative descriptions、Fibers は reconciler の work と state の persistent 表現です。「Virtual DOM」は有用な高レベル語ですが、React 内部は単純な virtual nodes ツリー以上に具体的です。

「Fiber は毎 render を速くする」 — 必ずしもそうではありません。Fiber は scheduling と bookkeeping を増やします。主な利点は単一 render スループットではなく、大きいか lower-priority updates 中に work を優先し browser blocking を避ける能力です。

「Concurrent は parallel だ」 — この文脈では違います。React は依然 main thread 上で JavaScript work を調整します。第 4 節のとおり concurrency は work を interleave、yield、obsolete renders を discard できること——rendering が別 thread に移ることではありません。

「Fiber は React Three Fiber だ」 — 別物です。React Fiber は React 内部 reconciliation architecture。React Three Fiber は同じ component model を Three.js scene graph に適用する community renderer で、名前が由来です。



最終的なメンタルモデル

私が使う最短で accurate なモデル:


Elements describe.
Fibers remember.
Queues collect.
Lanes prioritize.
Rendering computes.
Reconciliation matches.
Committing publishes.
Effects synchronize.

Components は自分を更新しません。一 state snapshot 用 description を返します。React は those functions 外に persistent state を保持し updates を queue し、複数 possible futures を計算し得ます。Reconciliation がどの component identities が生き残るか決めます。commit phase が一 finished future を current にします。

Concurrent React は上に載った別 rendering model ではありません。render が pure で commit と分離されているから可能になること:React は pause、restart、prioritize、suspend、discard でき visible interface を壊しません。

公開ルールはその architecture から続きます。rendering は speculative なので pure に。keys は stable に——identity が state を制御するから。queued state に依存する work には updater functions。Effects は commit 後に走る synchronization として扱う。render 回数に依存しない——attempt は abandon されうるから。

この model 上の新 API は What's New in React 19 を参照。主要 reference は Andrew Clark の React Fiber architecture notes と React ドキュメント render and commitstate snapshotsstate update queuespreserving stateEffectstransitionsSuspensehydration です。

この記事の実装詳細は React 19.2.7 に対応します。関連ソースは ReactFiber.jsReactFiberWorkLoop.jsReactFiberBeginWork.jsReactFiberCompleteWork.jsReactChildFiber.jsReactFiberHooks.jsReactFiberLane.js です。それらは今日の mechanism を説明するもので API 契約ではありません。