ホームページ  >  記事  >  ウェブフロントエンド  >  React の diff メソッドとは何ですか?

React の diff メソッドとは何ですか?

藏色散人
藏色散人オリジナル
2023-01-03 13:50:211810ブラウズ

react の diff メソッドは、ノードを可能な限り再利用する目的で 2 つのオブジェクト間の違いを見つけるために使用できます。diff アルゴリズムは調整の具体的な実装であり、調整とは仮想オブジェクトの変換を指します。 DOM ツリーへの実際の DOM ツリーの最小限の操作プロセス。

React の diff メソッドとは何ですか?

#このチュートリアルの動作環境: Windows 10 システム、react18.0.0 バージョン、Dell G3 コンピューター。

react の diff メソッドとは何ですか?

1. Diff アルゴリズムの役割

実際の DOM のレンダリングは非常にコストがかかります。特定のデータを変更して実際の DOM に直接レンダリングすることがあります。 DOM ツリー全体が再描画され、再配置されます。 DOM 全体ではなく、変更した DOM の小さな部分のみを更新したいと考えていますが、diff アルゴリズムはこれを実現するのに役立ちます。

diff アルゴリズムの本質は、ノードを可能な限り再利用することを目的として、2 つのオブジェクト間の違いを見つけることです。
注: ここで言及されているオブジェクトは、実際には vue の仮想 dom (仮想 dom ツリー) を指します。つまり、js オブジェクトを使用してページ内の dom 構造を表します。

2. React の差分アルゴリズム

1、 # 和解とは##?

仮想 DOM ツリーを変換するための の最小数実際の DOM ツリー この操作のプロセスはリコンシリエーションと呼ばれます。

2. React diff アルゴリズムとは何ですか?

diff アルゴリズムは、 調整の具体的な実装です。 。

3. 差分戦略

##React は 3 つの主要な戦略を使用して、O(n3) の複雑さを # に変換しますO(n) 複雑さ (1)

# 戦略 1 (##ツリーの差分): Web UI では DOM ノードのクロスレベル移動操作はほとんどないため、無視できます。

(2) 戦略 2 (コンポーネントの差分):同じクラスを持つ 2 つのコンポーネントは同様のツリー構造を生成します。 #異なるクラスを持つ 2 つのコンポーネントは異なるツリー構造を生成します。

(3) 戦略 3 (要素の差分): 同じレベルの子ノードのグループは、一意の ID によって区別されます。

React の diff メソッドとは何ですか?

4. ツリーの差分:

#(1) React は updateDepth を使用して、仮想 DOM ツリーの階層制御を実行します # ##########。 (2) ツリーを階層的に比較します。2 つのツリーは

ノードのみを比較します。同じレベルの # が比較されます。ノードが存在しない場合、そのノードとその子ノードは完全に削除され、それ以上の比較は行われません。 #(3) DOM ツリー全体の比較を完了するために必要な走査は 1 回だけです。

DOM ノードでクロスレベル操作が発生した場合、Diff はどうしますか?

回答: ツリー DIFF はツリーの各層を横断します。コンポーネントが存在しなくなった場合、コンポーネントは直接破棄されます。図に示すように、左側が古い属性、右側が新しい属性です。最初の層は R コンポーネントであり、まったく同じで変更されません。2 番目の層はコンポーネント DIFF に入り、同じ型です。コンポーネントの比較を続けますが、A コンポーネントが存在しないことが判明したので、コンポーネント A、B、C を直接削除し、引き続き 3 階層目に進み、コンポーネント A、B、C を再作成します。

上の図に示すように、A をルート ノードとするツリー全体は移動されるのではなく再作成されるため、公式にはこれを行わないことをお勧めします。 DOM ノードは複数のレベルにわたって動作し、実際に DOM ノードを削除または追加する代わりに、CSS を使用してノードを非表示にしたり表示したりすることができます。

React の diff メソッドとは何ですか?

##5. コンポーネントの差分 :

#React には、異なるコンポーネントを比較するための 3 つの戦略があります

##(1) 同じタイプ 2 つのコンポーネントについては、元の戦略 (階層比較) に従って仮想 DOM ツリーの比較を続けるだけです。

(2) 同じタイプの 2 つのコンポーネントの場合、コンポーネント A がコンポーネント B に変更されても、仮想 DOM はまったく変更されない可能性があります。これを知っていれば (仮想 DOM は変更中に変更されません)変換処理)、計算時間を大幅に節約できるため、ユーザーは shouldComponentUpdate() を使用して判定計算が必要かどうかを判断できます。

(3) 異なるタイプのコンポーネントは、(変更される) コンポーネントをダーティ コンポーネントとして決定し、それによってコンポーネント全体のすべてのノードを置き換えます。 ##################### ############知らせ:############### 上図に示すように、

コンポーネント D がコンポーネント G に変更されると、たとえ 2 つのコンポーネントが類似した構造を持っていたとしても、

React は D と G が異なるタイプのコンポーネントであると判断すると、コンポーネント D を直接削除し、コンポーネント G とそのサブノードを再作成する代わりに、比較は行いません。 React の diff メソッドとは何ですか?種類の異なるコンポーネントが似たような構造をしている場合、差分アルゴリズム解析を行うとパフォーマンスに影響しますが、結局のところ、異なる種類のコンポーネントが似たようなDOMツリーを持っているという状況は実際の開発プロセスではほとんど起こらないので、これは極端な要因 実際の開発プロセスに大きな影響を与えることは困難です。

#6、##要素の差分

##ノードが同じレベルにある場合、diff は 3 つのノード操作を提供します: 削除、

# を挿入、移動します。 ################## ###############入れる############### # #:コンポーネント C はセット (A、B) にないため、挿入する必要があります ##削除: ##(1) コンポーネント D がセット内にあります(A、B、D) ですが、D のノードは変更されており、再利用および更新できないため、古い D を削除して新しいノードを作成する必要があります。

(2) コンポーネント D は以前はセット (A、B、D) 内にありましたが、セットは新しいセット (A、B)、D になりました。削除する必要があります。 移動: コンポーネント D はすでにコレクション (A、B、C、D) であり、セットが更新されると、D は更新されませんが、位置は変わります。たとえば、新しいセット (A、D、B、C) では、D は 2 番目にあります。従来の差分のように行う必要はありません。古いセットの 2 番目の B と新しいセットの 2 番目の D を比較し、2 番目の位置の B を削除し、2 番目の位置に D を挿入し、一意のキー (同じレベルの同じグループの子ノード用) 区別するには、移動するだけです。

移動

状況1:

#新旧セットに同じノードが存在するが位置が異なる場合のノードの移動方法

#

React の diff メソッドとは何ですか?

(1) B は移動しません。詳細はありません。最後に更新します。stIndex=1

(2) 新しいコレクションは E を取得しますが、古いコレクションが存在しないことが判明したため、lastIndex=1 の位置に E を作成し、lastIndex=1# を更新します。

##(3) 新しいセットは C を取得します。C は移動せず、lastIndex=2

(4) を更新します。新しいセットは A を取得し、A が移動します。上記と同様に、lastIndex=2

(5) を更新します。新しいセットを比較した後、古いセットを走査します。新しい集合には要素がないが、古い集合には要素があると判断され(Dなど、新しい集合には要素がないが、古い集合には要素がある)、Dが見つかり、Dが削除され、diffが返されます。操作が終了します。


React での Diff アルゴリズム実装のコード:

_updateChildren: function(nextNestedChildrenElements, transaction, context) {
    var prevChildren = this._renderedChildren;
    var removedNodes = {};
    var mountImages = [];
    // 获取新的子元素数组
    var nextChildren = this._reconcilerUpdateChildren(
      prevChildren,
      nextNestedChildrenElements,
      mountImages,
      removedNodes,
      transaction,
      context
    );
    if (!nextChildren && !prevChildren) {
      return;
    }
    var updates = null;
    var name;
    var nextIndex = 0;
    var lastIndex = 0;
    var nextMountIndex = 0;
    var lastPlacedNode = null;
    for (name in nextChildren) {
      if (!nextChildren.hasOwnProperty(name)) {
        continue;
      }
      var prevChild = prevChildren && prevChildren[name];
      var nextChild = nextChildren[name];
      if (prevChild === nextChild) {
        // 同一个引用,说明是使用的同一个component,所以我们需要做移动的操作
        // 移动已有的子节点
        // NOTICE:这里根据nextIndex, lastIndex决定是否移动
        updates = enqueue(
          updates,
          this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex)
        );
        // 更新lastIndex
        lastIndex = Math.max(prevChild._mountIndex, lastIndex);
        // 更新component的.mountIndex属性
        prevChild._mountIndex = nextIndex;
      } else {
        if (prevChild) {
          // 更新lastIndex
          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
        }

        // 添加新的子节点在指定的位置上
        updates = enqueue(
          updates,
          this._mountChildAtIndex(
            nextChild,
            mountImages[nextMountIndex],
            lastPlacedNode,
            nextIndex,
            transaction,
            context
          )
        );
        nextMountIndex++;
      }
      // 更新nextIndex
      nextIndex++;
      lastPlacedNode = ReactReconciler.getHostNode(nextChild);
    }
    // 移除掉不存在的旧子节点,和旧子节点和新子节点不同的旧子节点
    for (name in removedNodes) {
      if (removedNodes.hasOwnProperty(name)) {
        updates = enqueue(
          updates,
          this._unmountChild(prevChildren[name], removedNodes[name])
        );
      }
    }
  }

3. Diff# に基づく開発の提案

##Based on Tree diff:

コンポーネントを開発するときは、DOM 構造の安定性を維持すること、つまり DOM 構造を最小限に動的に操作することに注意してください。可能な限り、特にモバイル操作を重視します。
  • ノードの数が多すぎる場合、またはページの更新数が多すぎる場合、ページの遅延がより顕著になります。
  • 現時点では、実際に DOM ノードを削除または追加する代わりに、CSS を使用してノードを非表示または表示できます。
コンポーネントの差分に基づく:

コンポーネントの不要な更新を減らすために shouldComponentUpdate() の使用に注意してください。
  • 同様の構造は可能な限りコンポーネントにカプセル化する必要があります。これにより、コードの量が削減されるだけでなく、コンポーネント diff のパフォーマンス消費も削減されます。
要素の差分に基づく:

リスト構造の場合は、最後のノードをリストの先頭に移動するなどの操作を減らすようにしてください。ノード数が超過した場合 更新操作が多すぎたり、頻度が高すぎると、React のレンダリング パフォーマンスにある程度の影響を与えます。
  • 推奨学習: 「
react ビデオ チュートリアル

以上がReact の diff メソッドとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。