目次
1. Diff アルゴリズムとは
ホームページ ウェブフロントエンド jsチュートリアル React の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装

React の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装

Sep 28, 2018 pm 05:27 PM
html html5 javascript react.js フロントエンド

この記事の内容は、React の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装には一定の参考値がありますので、困っている方は参考にしていただければ幸いです。

1. Diff アルゴリズムとは

  • 従来の Diff: diff アルゴリズムは、HTML DOM 構造の差分検索アルゴリズムです。ツリーアルゴリズムの検索、および 2 つのツリーの差を計算する時間計算量は O(n^3) ですが、これは明らかにコストが高すぎるため、この従来のアルゴリズムを React が採用することは不可能です。

  • React Diff:
  • 前述したように、React は仮想 DOM テクノロジーを使用して実際の DOM をマッピングします。つまり、DOM の差分検索です。 React Diff アルゴリズムは、本質的に 2 つの JavaScript オブジェクトの差分検索を比較することです。
    • 3 つの戦略に基づいています。 Web UI での DOM ノードのレベル移動操作 非常に小さいため、無視できます。 (ツリー差分)
    • #同じクラスを持つ 2 つのコンポーネントは同様のツリー構造を生成し、異なるクラスを持つ 2 つのコンポーネントは異なるツリー構造を生成します (コンポーネント差分)

    同じレベルにある子ノードのグループは、一意の ID によって区別できます。 (要素 diff)
  1. 2. React Diff アルゴリズムの解釈

  2. まず、Diff が次のことを行うことを明確にする必要があります。 React 更新フェーズのアルゴリズムの適用中にのみ発生します。

React 更新メカニズム:

  • ##React Diff アルゴリズム最適化戦略チャート:

React の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装

    ##React 更新フェーズでは、ReactElement のタイプを決定し、さまざまな操作を実行します。ReactElement のタイプには、テキスト、Dom、およびコンポーネントの 3 つのタイプが含まれます。 :
カスタム要素の更新は主にレンダリングされたノードを更新することであり、店主はレンダリングされたノードの対応するコンポーネントに更新の管理を任せます。

React の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装テキスト ノードの更新は非常に簡単で、コピーを直接更新するだけです。

  • ブラウザの基本要素の更新は 2 つの部分に分かれています:

  • 属性の更新、以前との比較属性以降 異なる、部分的な更新。また、イベント バインディングなどの特別なプロパティを処理します。
    • 子ノードの更新は、主に差分オブジェクトを見つけるために行われます。その場合は、上記の shouldUpdateReactComponent も使用されます。直接更新できる場合は、再帰的に子ノードの更新を呼び出します。これにより、差分オブジェクトも再帰的に検索されます。以前のオブジェクトの削除や新しいオブジェクトの追加を直接更新することはできません。そして、差分オブジェクトを元にDOM要素の操作(位置変更、削除、追加等)を行います。
    • 実際、Diff アルゴリズムは React 更新フェーズの DOM 要素更新プロセス中にのみ呼び出されます。 ?

  1. #1. テキスト タイプが更新され、内容が異なる場合は、複雑な Diff アルゴリズムを呼び出すことなく、直接更新および置換されます。

     ReactDOMTextComponent.prototype.receiveComponent(nextText, transaction) {
        //与之前保存的字符串比较
        if (nextText !== this._currentElement) {
          this._currentElement = nextText;
          var nextStringText = '' + nextText;
          if (nextStringText !== this._stringText) {
            this._stringText = nextStringText;
            var commentNodes = this.getHostNode();
            // 替换文本元素
            DOMChildrenOperations.replaceDelimitedText(
              commentNodes[0],
              commentNodes[1],
              nextStringText
            );
          }
        }
      }
    ログイン後にコピー
  2. 2. カスタム コンポーネント要素の場合:

    class Tab extends Component {
        constructor(props) {
            super(props);
            this.state = {
                index: 1,
            }
        }
        shouldComponentUpdate() {
            ....
        }
        render() {
            return (
                <p>
                    </p><p>item1</p>
                    <p>item1</p>
                
            )
        }
        
    }
    ログイン後にコピー
明確にする必要があるのは、コンポーネントとは何かということです。コンポーネントは単なる Html 構造のパッケージング コンテナであり、この Html 構造のステータスを管理する機能があります。たとえば、上記の Tab コンポーネント: その重要な内容です。は render 関数によって返される Html 構造であり、Tab クラスと呼ばれるものは、この Html 構造のパッケージング コンテナーです (
  • ご存知のとおり、パッケージング ボックスとして理解できます)。 React レンダリング メカニズムの図を参照してください。カスタム コンポーネントは最終的に React Diff 最適化戦略 1 と結合されます (異なるクラスの 2 つのコンポーネントは異なる構造を持っています)

3 基本要素:

ReactDOMComponent.prototype.receiveComponent = function(nextElement, transaction, context) {
    var prevElement = this._currentElement;
    this._currentElement = nextElement;
    this.updateComponent(transaction, prevElement, nextElement, context);
}

ReactDOMComponent.prototype.updateComponent = function(transaction, prevElement, nextElement, context) {
    //需要单独的更新属性
    this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag);
    //再更新子节点
    this._updateDOMChildren(
      lastProps,
      nextProps,
      transaction,
      context
    );

    // ......
}
ログイン後にコピー

この中で、diff アルゴリズムは _updateDOMChildren メソッドで内部的に呼び出されます。

  • 3. 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])
            );
          }
        }
      }
    ログイン後にコピー
    4. Diff に基づく開発提案
  • ツリー差分に基づいてコンポーネントを開発する場合:

、DOM 構造の安定性を維持することに注意してください。つまり、DOM 構造の動的操作をできる限り少なくすることです (特にモバイル)。オペレーション。

    ノードの数が多すぎる場合、またはページの更新回数が多すぎる場合、ページの遅延がより顕著になります。
  • 現時点では、DOM ノードを実際に削除または追加する代わりに、CSS を使用してノードを非表示または表示できます。

    コンポーネントの差分に基づく
  • :

  1. コンポーネントの不要な更新を減らすために shouldComponentUpdate() の使用に注意してください。

  2. 同様の構造は可能な限りコンポーネントにカプセル化する必要があります。これにより、コードの量が削減されるだけでなく、コンポーネント diff のパフォーマンス消費も削減されます。

  • 要素の差分に基づく:

    1. リスト構造の場合は、最後の要素を減らすようにしてください。ノード数が多すぎる場合や更新頻度が高すぎる場合、ノードをリストの先頭に移動する操作は React のレンダリング パフォーマンスにある程度影響します。

    以上がReact の Diff アルゴリズムとは何ですか? Diff アルゴリズムの戦略と実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    HTMLの表の境界線 HTMLの表の境界線 Sep 04, 2024 pm 04:49 PM

    HTML の表の境界線に関するガイド。ここでは、HTML でのテーブルの境界線の例を示しながら、テーブル境界線を定義する複数の方法について説明します。

    HTML のネストされたテーブル HTML のネストされたテーブル Sep 04, 2024 pm 04:49 PM

    これは、HTML でのネストされたテーブルのガイドです。ここでは、テーブル内にテーブルを作成する方法をそれぞれの例とともに説明します。

    HTML 左マージン HTML 左マージン Sep 04, 2024 pm 04:48 PM

    HTML マージン左のガイド。ここでは、HTML margin-left の概要とその例、およびそのコード実装について説明します。

    HTML テーブルのレイアウト HTML テーブルのレイアウト Sep 04, 2024 pm 04:54 PM

    HTML テーブル レイアウトのガイド。ここでは、HTML テーブル レイアウトの値と例および出力について詳しく説明します。

    HTML入力プレースホルダー HTML入力プレースホルダー Sep 04, 2024 pm 04:54 PM

    HTML 入力プレースホルダーのガイド。ここでは、コードと出力とともに HTML 入力プレースホルダーの例について説明します。

    HTML 順序付きリスト HTML 順序付きリスト Sep 04, 2024 pm 04:43 PM

    HTML 順序付きリストのガイド。ここでは、HTML 順序付きリストと型の導入とその例についても説明します。

    HTML の onclick ボタン HTML の onclick ボタン Sep 04, 2024 pm 04:49 PM

    HTML オンクリック ボタンのガイド。ここでは、それらの紹介、動作、例、およびさまざまなイベントでの onclick イベントについてそれぞれ説明します。

    HTML 内のテキストの移動 HTML 内のテキストの移動 Sep 04, 2024 pm 04:45 PM

    HTML でのテキストの移動に関するガイド。ここでは、概要、マーキー タグが構文でどのように機能するか、および実装例について説明します。

    See all articles