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 文の実行時間を表示する方法

推薦する

IE8を閲覧するときにウェブサイトが自動的にIE7互換モードを使用するようにする

序文IE の将来のすべてのバージョンで Web ページの外観が一貫していることを保証するために、IE...

Vue 監視属性のグラフィック例の詳細な説明

目次リスナープロパティとは何ですか?リスニングプロパティと計算プロパティの違いは何ですか?監視プロパ...

Dockerコンテナとローカルマシン間でファイルを転送する方法

ホストとコンテナ間でファイルを転送するには、コンテナの完全な ID が必要です。取得方法は以下の通り...

Dockerでnginxを実行し、ローカルディレクトリをイメージにマウントする方法

1 hupからイメージを取得する docker プル nginx 2 マウントするディレクトリを作成...

私が良いと思うクールなデザインサイトをいくつかまとめてみました。

ウェブサイトをデザインするにはインスピレーションが必要です。良いインスピレーションを得るには、より多...

無効にするとフォームの入力が送信できない問題の解決方法

以前、追加と変更を一緒に記述したテストプログラムを書いたことがあります。変更が必要な場合は、フォーム...

ウェブページレイアウトデザインのシンプルな原則

この記事では、Web ページ レイアウト デザインのいくつかの簡単な原則をまとめ、Web ページ デ...

入力のsize属性とmaxlength属性の違い

最近、プロジェクトで input size 属性と maxlength 属性を使用しました。以前は、...

vue keepAlive キャッシュクリア問題事例の詳細な説明

Keepalive は Vue プロジェクトでのキャッシュによく使用され、基本的な要件を満たすのに非...

Dockerコンテナのインポ​​ートとエクスポートに関するチュートリアル

背景Docker の人気は、コンテナの共有と移植が容易であることと密接に関係しています。ユーザーは、...

MySQL グローバルロックとテーブルレベルロックの具体的な使用法

目次序文グローバルロックテーブルロックテーブルロックメタデータ ロック (MDL ロック)要約する参...

CentOS 8で自動更新を設定するための手順を完了する

データとコンピューターに対してできる最善のことは、それらを安全に保つことです。アップデートを有効にす...

サラウンドリフレクションロード効果を実現するHTML+CSS

この記事では、主に html + css を使用してサラウンド リフレクション ローディング エフェ...

Docker で Portainer ビジュアル インターフェースを構築するための詳細な手順

前回述べた問題を解決するために、オンラインで検索したところ、非常に優れたビジュアル インターフェース...

入力タイプ=ファイルスタイルを定義する方法

ファイルコントロールを美しくする理由は何ですか?他の子供たちはみんなきちんとしたきれいな服を着ている...