👌

React Fiberとは

2023/08/13に公開

今更ながらReact Fiberを調べてみました。
実際にReactを書くだけなら知らなくても書けてしまいますが、概念や仕組みを知ることでより効率的に記述できることもあると思います。
ということで今回はReact Fiberとは何なのかを備忘録も兼ねて概要をまとめてみます。

React Fiberとは

React FiberとはReact16からの新しいReconciliation Engineで、古いReconciliationを完全に後方互換性を持って書き直したものです。レンダリング作業を分割し、複数のフレームに分散させる機能を持っています。
この新しい、Reconciliation AlgorithmFiber Reconcilerと呼ばれます。
この名前は、DOMツリーのノードを表すのに使われるFiberに由来します。

Reconciliationとは

React Fiberを理解するにあたってReconciliationがそもそも何なのかを理解する必要があります。
Reconciliationとは、Current Tree(現在の仮想DOM)とWorkInProgress Tree(新しい仮想DOM)2つのTreeを再起的に比較して差分を計算し、実際のDOMに必要な更新を行うプロセスのことを指します。
React16以降のReconciliationFiber Reconcilerと呼ばれ、それ以前のものはStack Reconcilerと呼ばれます。

Stack Reconcilerとは

Fiber Reconcilerが何であるかを理解しやすくするためにStack Reconcilerが何なのかを簡単に説明します。
現在の仮想DOMと新しい仮想DOMを比較し差分を計算する部分においてはどちらも同じですが、Stack Reconcilerは同期的に差分の計算を行っています。これは1つの欠点であり、現在の仮想DOMと新しい仮想DOMの差分検知が行われる間スレッドを占有してしまっていました。
そのため、すべてのイベントは差分検知が終了するまで待機する必要があります。
https://legacy.reactjs.org/docs/implementation-notes.html

Fiber Reconcilerとは

Fiber ReconcilerStack Reconcilerの欠点を解消したAlgorithmで下記のような機能を持ち合わせています。

  • 差分検知の作業をFiber単位で行うことができ、複数のフレームに分散できる
  • 新しい更新が入ってきた時に作業を一時停止、中断、再利用できる
  • 更新をする際に優先順位を割り当てられる

これらのことを行うには作業自体を小さく分解する必要があります。この実行する作業の単位をFiberと呼びます。

Fiber

実行する作業の単位を表します。React要素はすべてFiber Nodeに変換されます。
Fiber Nodeは最初のレンダリングでのみ作成され、それ以降は、すでに作成されたFiberがコンポーネントの状態を保持します。
状態の保持に関してはこちら。
https://react.dev/learn/preserving-and-resetting-state#challenges
また、上述した通り作業を一時停止、中断、再利用を行うために、それぞれのFiberには優先順位が割り当てられます。

Fiber Tree

それぞれのFiberを保持するものをFiber Treeと呼びます。
下記のようなComponentは図1のようなFiber Treeになります。

    <div>
      <h1>Hello world</h1>
      <div>
        <p>
          hoge
        </p>
      </div>
    </div>

図1

  • child
    それぞれのFiberは、最初のComponentへの参照のみ持ちます。図1では黒矢印で表されています。

  • sibling
    それぞれのFiberは、次の兄弟への参照を持ちます。図1では青矢印で表されています。

  • return
    それぞれのFiberは、親への参照を持ちます。図1では赤矢印で表示されています。

その他のFiber Nodeのプロパティは以下を参考にしてください
https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiber.js#L136

このFiber Treeをトラバースし差分を検知します。トラバースは下記の順番で行なわれます。

  • Start
    root要素から開始。そのためのFiberを作成します。

  • Child
    親要素から、最初の子要素にトラバースします。これはリーフ要素に到達するまで再起的に行われます。

  • Sibling
    リーフ要素に到達すると、その要素に兄弟要素があるかどうかチェックします。もしあれば、Startから開始します。

  • Return
    兄弟要素がない場合、親要素に戻ります。

上記のようにそれぞれのFiberが次のFiberへのポインタを持っているため、作業を一時停止したり再開することができるのです。
またこれらの作業は以下のタイミングで実行されます。

  • Initial Render Phase
    初期レンダー時。React要素毎にFiberが作成されます。

  • Render Phase
    Comoponentの状態変更など、Applicationの全ての更新に対して呼び出されます。このとき現在のCurrent Treeを持っています。新しく作成したツリーをWorkInProgress Treeと呼びます。
    このフェーズでは、Current Treeがルートからリーフまでトラバースされ、ツリー内の既存のFiberが更新され、新しいstateとpropで処理されます。このフェーズは非同期であり、現在処理中のFiberの優先度よりも高い優先度で更新されたFiberが間に入ると、その間に中断することができます。
    その場合、優先順位の高いタスクが処理されるように、Fiberの処理を停止または中断することができます。

  • Commit Phase
    完成したFiber TreeがUIにレンダリングされます。ブラウザのDOMが再描画されるフェースです。
    このフェーズは同期的に実行され、一度Commitが始まると中断することはできません。
    このフェーズが完了するとWorkInProgress TreeはCurrent Treeとしてマークされます。

まとめ

React Fiberとはレンダリング作業を分割し、複数のフレームに分散させる機能を持った新しいReconciliation Algorithmだと言うことが分かりました。
他にもScheduling機能やeventに優先順位をつけるのはいつやってるかなどまとめたいことがあるのですが、長くなりそうなので今回は省きました。
また機会があればまとめてみようと思います。

参照

https://medium.com/@pnk.tanwar/react-fiber-secret-ingredient-in-reacts-reconciliation-6f156be43dcc
https://github.com/acdlite/react-fiber-architecture#react-fiber-architecture
https://react.dev/learn/preserving-and-resetting-state#challenges

Discussion