React の調整アルゴリズム Diffing アルゴリズム戦略の詳細な説明

React の調整アルゴリズム Diffing アルゴリズム戦略の詳細な説明

アルゴリズム戦略

React の調整アルゴリズムは主にレンダリング段階で発生します。調整アルゴリズムは特定のアルゴリズム機能ではなく、調整プロセスで採用される戦略を指し、workInProcess ツリーの構築パフォーマンスと Dom ツリーの更新パフォーマンスを向上させます。これは、差分アルゴリズムとも呼ばれます。 React の公式サイトで「Diffing」アルゴリズムを説明する際に、「2 つのツリーを比較する」と書かれていますが、ソース コードを実装する際には、2 つのツリーを作成してから、2 つのツリーを上から下に比較するわけではありません。この差分は子ノードを構築するときに発生し、実際には新しく生成された ReactElement と現在のツリー上の fibe ノードの差分になります。 差分アルゴリズムの時間計算量を O(n) 以内に抑えるために (ツリー差分の時間計算量にはツリーの編集距離が関係します。こちらを参照)、次の戦略が採用されています。

同じレベルのノードのみを比較します(公式ウェブサイトでは言及されていないようです)

単一ノードの比較では、現在のノード タイプとキーが同じでない場合、その子ノードを比較せず、ノードとそのサブツリー全体を直接削除し、ReactElement に従ってノード ツリーを再生成します。 React では、異なるタイプのコンポーネントは異なるツリー構造を生成するため、再利用する必要はないと考えられています。

子ノードが配列の場合、一意のキー値に基づいてノードを検索および比較できるため、子ノードの順序が変更されても、キー値に基づいて再利用できます。

すべてのノード比較ではキーが比較され、キーのデフォルト値は null であることに注意してください。設定されていない場合、null は常に null と等しくなり、キーは同じであると見なされます。

単一ノードの差分

単一のノードを比較すると、fibe.elementType と ReactElement.type、fibe.key と ReactElement.key の 2 つの属性セットが比較されます。これらの 2 つの属性セットが等しい場合、データ構造の物理スペースには次の再利用ロジックが適用されます (詳細については、ソース コードの reconcileSingleElement 関数を参照してください)。

  1. 現在のファイバーに代替ノードがある場合 (つまり、このファイバー ノードが以前に調整に参加していた場合)、代替ノードの物理スペースが再利用されます。それ以外の場合は、現在のファイバー ノードを複製して新しい物理スペースを占有する必要があります。
  2. 対応するインスタンスまたはDOMが再利用されます
  3. 現在のファイバーの下の子ツリーも直接マウントされます(次のステップで子ノードを再帰するときに使用されます)

2 つの属性セットのいずれかが等しくない場合:

  • fibeはReactElementに基づいて再作成されます
  • 対応するインスタンスとDomも再構築されます
  • すべての子ツリーを削除します。

生成された ReactElement が単一のノードであるが、対応する現在のツリーに複数のノードがある場合、一致するものがあるかどうかを 1 つずつ検索します。一致するものが見つかった場合は、その他は削除されます。一致するものが見つからない場合は、すべてが削除されます。たとえば、Couter コンポーネントには、クリック数が 10 を超えるとクリック ボタンを非表示にするロジックがあります。 10 回目に達すると、スパン ノードが再利用されます。

クラス Counter は React.Component を拡張します {
    状態={
        カウント:0
    }
    追加カウント = ()=>{
        定数 count = this.state.count+1;
        this.setState({count})
    }
    コンポーネントの更新(){
        console.log("更新されました")
    }
    与える(){
        this.state.count < 10 を返します? [
            <button onClick={this.addCount}>クリック</button>
            <span>クリック数: {this.state.count}</span>
        ]:<span>クリック数: {this.state.count}</span>;
    }
}

配列ノードの差分

配列ノードを比較する場合、プロセスはより複雑になります: (ソースコードについては reconcileChildrenArray 関数を参照してください)

途中に 2 つの重要なトラバーサルがあります。1 つ目はインデックスによるトラバーサルで、新しいノードと古いノードを順番に比較し、キー値の不一致が見つかった場合はすぐにトラバーサルを中断します。 2 回目のトラバーサルでは、残りの古いノードに対して「キー - ノード」マップ テーブルが作成され、残りの新しいノードがトラバースされ、比較のためにキー値に従ってテーブルから古いノードが検索されます。以下は、3 つのケースにおける新旧ノードのマッチングと比較です。

キー値の使用要件

単一ノードと配列ノードの差分の観点から、キー値は主に新規作成を減らすために使用されます。比較中に新しいノードと古いノードが一致するようにするには、キー値を使用するときに次の点に注意する必要があります。

  1. 安定している必要があります。キー値が毎回変わる場合(たとえば、乱数が使用される場合)、差分取得時に新しいセクションと古いセクションが一致せず、大量の新規作成が発生します。
  2. 一意である必要があります。キー値が一意でない場合、「キー - ノード」マップ テーブルの作成時にキー値が見落とされ、混乱が生じ、ページ更新エラーが発生します。

単一ノードの場合、キー値は差分取得時にも使用されます。無駄だと思わずに、適当に設定してください。 単一ノードのキー値を使用してコンポーネントの破壊と再構築を実現する非標準の使用法もいくつかありますが、この使用法は React の設計コンセプトに沿っていません。

たとえば、ログ データを内部的に取得し、外部データに依存しないログ コンポーネントがあります。ただし、要件が反復されると、同じページに承認操作が追加されます。承認後、新しいログ データがバックエンドに追加されます。この時点で、フロントエンド ページに新しく追加されたログ データをリアルタイムで表示し、ログ コンポーネントをトリガーしてデータを再度取得する必要があります。問題を解決するためにデータを上方に昇格する方法を使用しない場合は、コンポーネントにランダムなキーを割り当てることができます。承認操作が完了したら、キー値を変更すると、コンポーネントが再構築されます。ただし、この方法はオーバーヘッドが大きく、コンポーネント ツリー全体が破棄され、再構築されます。代わりに他のソリューションを使用することもできます。たとえば、コンポーネントの ref を指定できます。承認が完了したら、ref を通じてコン​​ポーネントの refresh 関数を呼び出して、データを再取得し、コンポーネントを更新します。

配列ノードの場合、キー値は主に子ノードの位置に大きくずれがある場合に重要な役割を果たします。 最後に通常の追加と削除を行う場合、最初のインデックス トラバーサルでマッチングが完了し、2 番目のキー マップ トラバーサルには入りません。 キーと値のペアは「安定」かつ「一意」である必要があるため、フロントエンドでは通常、バックエンドがリスト データの一意の識別子を提供する必要があります。集計インターフェイスの場合、これによりバックエンドに余分な作業が追加されます。この場合、まずデータの変化する特性を理解してから、キーを設定する必要があるかどうかを判断できます。

上記のログコンポーネントの場合、ログはリストです。新しく追加されたログは最初の行に挿入されます。キーが設定されていない場合は、基本的にすべての子ノードを更新する必要があります。キーが設定されている場合、バックエンド サービスは各ログに ID などの「永久的な」一意の識別子を追加する必要があります。かつて、データの更新時にキー値の一意性が変わったためにページの表示がおかしくなるというケースを経験したことがあります。

React の reconciliation algorithm (Diffing algorithm) に関するこの記事はこれで終わりです。React Diffing algorithm に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Reactのdiffアルゴリズムの詳細な分析
  • Reactの仮想DOMとdiffアルゴリズムの詳細な説明
  • React diffアルゴリズムソースコード分析
  • ReactアプリケーションにおけるDOM DIFFアルゴリズムの詳細な説明
  • ReactレンダリングプロセスからのDiffアルゴリズムの分析に関する簡単な説明
  • React diffアルゴリズムの実装例
  • React の Diff アルゴリズムをご存知ですか?

<<:  CSS スティッキーレイアウトを使用してヘッダーを上部に配置する方法

>>:  MySQL で SQL 文の実行時間を表示する方法

推薦する

Vue ページ内の公開マルチタイプ添付画像アップロード領域と適用可能な折りたたみパネル (サンプルコード)

フロントエンド プロジェクトでは、添付ファイルのアップロードは非常に一般的な機能であり、ほぼすべての...

Python Flask WeChat アプレットのログインプロセスとログイン API 実装コード

1. まずは効果を見てみましょうインターフェース要求によって返されるデータ: 2. 公式ログインフロ...

アイデアを使用して Springboot 初期化サーバーを構築する際の問題分析

問題の説明最近、Springbootプロジェクトを構築していたところ、会社のネットワークケーブルに接...

Dockerのオンラインおよびオフラインインストールと一般的なコマンド操作

1. テスト環境名前バージョンセント7.6ドッカー18.09.06 2. オンラインインストールここ...

Vue カスタム オプション時間カレンダー コンポーネント

この記事の例では、参考のためにvueカスタムオプションタイムカレンダーコンポーネントの具体的なコード...

ウェブサイトにファビコンを追加するためのヒント: URLの前の小さなアイコン

いわゆるファビコンは、Favorites Icon の略で、中国語ではウェブサイトアバターと呼ばれて...

IEの送信フォームの記録履歴クリックリターン情報を実現するためのCSSスタイルコントロールはまだ残っています

これは主に CSS スタイルのコントロールと META タグです。コードをコピーコードは次のとおりで...

Squid を使用して http および https 用のプロキシ サーバーを構築する方法

nginx を導入した際に、フォワードプロキシの設定も nginx を使っていました。しかし、htt...

Linux サーバーのクイックアンインストールとノード環境のインストール (簡単に始められます)

1.まずnpmをアンインストールする sudo npm アンインストール npm -g 2. ノー...

HTML独習の旅(I)基本要素と属性の練習(自分でコードを書く)

私は W3school のチュートリアルに従いました。チュートリアルはとても良いと思います。各セクシ...

mysql 3つのテーブルを接続してビューを作成する

3 つのテーブルが接続されています。テーブル A のフィールド a はテーブル B のフィールド b...

Vue のフィルターウィジェットの詳細な使用方法

この記事では、参考までにVue More Filter Itemウィジェットの実装方法を例として紹介...

Linux で大きなファイルの内容を消去または削除する 5 つの方法

Linux ターミナルでファイルを操作しているときに、Linux コマンドライン エディターでファイ...

プロセスのすべての情報を表示するLinuxメソッドの例

サーバー上にタスク プロセスがあります。 ps -ef | grep task を使用して表示すると...

Linux でテキストを表示するためのヒント (非常に実用的!)

序文日常の開発では、サーバー上でさまざまなテキストやログの表示操作を実行する必要があることがよくあり...