React のフックはファイバーの後に登場した機能であるため、フックはファイバーに依存して実装される必要があると誤解されています。実際には、この 2 つは必ずしも関連しているわけではありません。
現在、フックは React だけでなく、Preact、React ssr、Midway などのフレームワークでも実装されており、その実装はファイバーに依存しません。
これらのさまざまなフレームワークのフックがどのように実装されるかを見てみましょう。
React は、babel や tsc などのコンパイル ツールによってレンダリング関数にコンパイルされ、vdom を生成するために実行される jsx を通じてインターフェイスを記述します。
ここでのレンダリング関数は、React17 より前の React.createElement でした。
React 17 以降は jsx に変更されました。
この jsx ランタイムは自動的に導入されるため、以前のようにコンポーネントごとに React インポートを保持する必要はありません。
レンダー関数の実行により vdom が生成されます。
vdom の構造は次のようになります。
React16 より前では、この vdom は再帰的にレンダリングされ、実際の dom を追加、削除、変更していました。
React16 でファイバー アーキテクチャが導入された後、追加の手順が追加されました。まず vdom をファイバーに変換し、次にファイバーをレンダリングします。
vdom をファイバーに変換するプロセスはリコンサイルと呼ばれ、実際の dom を追加、削除、変更する最終プロセスはコミットと呼ばれます。
なぜそのような変換を行う必要があるのでしょうか?
vdom には子ノード child への参照のみがあり、親ノードparent および他の兄弟ノードへの参照がないため、中断することなく一度にすべての vdom ノードを dom に再帰的にレンダリングする必要があります。
中断された場合はどうなりますか?親ノードと兄弟ノードは記録されないため、子ノードの処理のみを続行できますが、vdom の他の部分は処理できません。
React がこの種のファイバー構造を導入したのはこのためです。このファイバー構造には、親ノードの戻り、子ノードの子、兄弟ノードの兄弟などの参照があり、中断と回復後に未処理のノードがすべて見つかるため、中断することができます。
ファイバーノードの構造は次のとおりです。
このプロセスは中断することができ、当然、スケジュールすることもできます。これがスケジュール プロセスです。
したがって、ファイバー アーキテクチャは、スケジュール、リコンサイル (vdom をファイバーに変換)、コミット (dom に更新) の 3 つの段階に分かれています。
関数コンポーネントでフックを使用して一部の値にアクセスでき、これらの値はファイバー ノードに保存されます。
たとえば、この関数コンポーネントでは 6 つのフックが使用されています。
次に、対応するファイバー ノード上に 6 つの要素の MemorydState リンク リストがあります。
次に連結します:
異なるフックは、memordState リンク リストの異なる要素の値にアクセスします。これが反応フックの原理です。
このリンクされたリストには作成フェーズと更新フェーズがあるため、useXxx の最終実装は mountXxx と updateXxx に分割されていることがわかります。
ここでのマウント フェーズでは、フック ノードを作成し、それらをリンク リストに組み立てます。
作成されたフック リンク リストは、ファイバー ノードの MemorydState 属性にリンクされます。
更新するときは、ファイバー ノードからこのフック リストを自然に取得できます。
このようにして、複数のレンダリングで、useXxx API はファイバー ノード上で対応する MemorydState を見つけることができます。
これが React フックの原理であり、ファイバーノードにフックが格納されていることがわかります。
では、プリアクトとの違いは何でしょうか?
Preact は、React コードと互換性のある、より軽量なフレームワークであり、フックなどの React 機能に加えて、クラス コンポーネントと関数コンポーネントをサポートします。ただし、ファイバー アーキテクチャは実装されていません。
それは、最終的なパフォーマンスではなく、主に最終的なサイズ (わずか 3 kb) を考慮しているためです。
React がファイバー ノードにフック リストを保存することを学びました。Preact にファイバー ノードがない場合、フック リストはどこに保存されるのでしょうか?
実際、ファイバーはパフォーマンスを向上させるために vdom を変更するだけであり、vdom と本質的な違いはないと考えられがちです。では、フックを vdom に保存すればよいのでしょうか。
実際、preact はフック リストを vdom に配置します。
たとえば、この関数コンポーネントには 4 つのフックがあります。
その実装は、vdom 上の対応するフックにアクセスすることです。
React のようにフックをマウントと更新の 2 段階に分割するのではなく、それらをマージして処理します。
図に示すように、component.__hooks の配列にフックを格納し、添字を通じてアクセスします。
このコンポーネントは vdom の属性です。
つまり、フックの値は vnode._component._hooks の配列に格納されます。
フックの実装における React と Preact の違いを比較してください。React
では、フック リストは FiberNode.memorizedState 属性に格納されます。Preact では、フック リストは vnode._component._hooks 属性に格納されます。React
のフック リストは連結されます。フックのリンク リストは配列です。React
ではフックのリンク リストの作成と更新をサブスクリプト アクセスによって分離します
フックの実装はファイバーに依存するものではなく、コンポーネントに対応するフック データを保存する場所を見つける必要があるだけで、レンダリング中に取得できる限り、保存場所は問題ではありません。
vdom、ファイバー、およびコンポーネントのレンダリングには強い関連性があるため、これらはこれらの構造に格納されます。
たとえば、react ssr がフックを実装する場合、それはファイバーにも vdom にも存在しません。react
実際には、csr に加えて、react-dom パッケージでも ssr を実行できます。react
の render メソッドを使用します。 csr の場合の dom:
ssr の場合、react-dom/server の renderToString メソッドまたは renderToStream メソッドを使用します。
vdom からファイバーへの変換は ssr 中に行われると思いますか?
ファイバーは、ブラウザーでの実行時のレンダリング パフォーマンスを向上させ、計算を中断可能にし、アイドル時に計算を実行するために導入された構造です。
サーバー側のレンダリングには当然ファイバーは必要ありません。
ファイバーが必要ない場合、フックリストはどこに保存されますか?ヴドム?
確かに vdom に配置できますが、そうではありません。
たとえば、useRef フックを使用します。
firstWorkInProgressHookからnextと連結したリンクリストです。
firstWorkInProgressHook は、createHook で作成された最初のフック ノードです。
vdom にはマウントされていません。
なぜ?
ssr は一度レンダリングするだけで済み、更新する必要がないため、vdom 上でハングアップする必要はありません。
各コンポーネントのフックの処理が完了するたびに、フック リストをクリアするだけです。
したがって、react ssr を使用する場合、グローバル変数にフックが存在します。
React csr と ssr のフックの実装原則の違いを比較してください。csr
では、ファイバーは vdom から作成され、レンダリングを中断可能にし、アイドル スケジューリングを通じてパフォーマンスを向上させるために使用されますが、ssr では、vdom によって直接レンダリングされません。
使用する場合
、フックはファイバー ノードに保存されますが、ssr を使用する場合、フックはグローバル変数に直接配置され、各コンポーネントが処理された後にクリアされます。 CSR は再度使用されないため
、フックの作成と更新はマウントと更新の 2 つのフェーズに分割されますが、SSR は 1 回だけ処理され、
フックの作成フェーズのみが実際には複雑ではありません
。つまり、特定のコンテキストでリンク リストをリンク リストに保存すると、フック API がリンク リストのさまざまな要素から対応するデータにアクセスして、それぞれのロジックを完了します。このコンテキストは、vdom、fiber、またはグローバル変数の場合もあります。
ただし、フックのアイデアは依然として非常に人気があります。淘宝網によって作成されたサーバー側フレームワーク Midway は、フックのアイデアを導入しています。Midway
Node.js フレームワークです。
サーバー側のフレームワークには当然 vdom や Fiber などの構造はありませんが、フックの考え方はこれらに依存しません。フック API を実装するには、特定のコンテキストにリンクされたリストを配置するだけです。
Midway は、反応フックに似た API を実装します。
フック リストが存在する場所を具体的に調べていませんが、フック リストを保存するコンテキストがある限り、フックの実装原理はすでに習得しています。
反応フックは、反応ファイバー アーキテクチャの後に登場した機能であり、フックはファイバーで実装する必要があると誤解しています。反応、プリアクト、反応 ssr、およびミッドウェイのそれぞれのフックの実装を調べたところ、次のことがわかりました。これは当てはまりません。react
それは実行されます。それで、反応フックはそれを実装するためにファイバーに依存する必要がありますか?
明らかにそうではありません。ファイバー、vdom、グローバル変数、さらにはあらゆるコンテキストでも使用できます。