Vue における v-for のキーの一意性の詳細な説明

Vue における v-for のキーの一意性の詳細な説明

1. DOM の違い

キー属性の重要性を本当に理解するには、まず DOM Diff から始める必要があります。DOM Diff の原理を深く理解する必要はなく、DOM Diff の動作プロセスを知るだけで十分です。

Vue と React はどちらも仮想 DOM を使用して、不要なブラウザ レンダリングを削減します。 Vue と React はどちらもビューをレンダリングするために v = render(m) メソッドを使用するため、モデル データが変更されると、DOM 要素が再レンダリングされてビューが更新されます。しかし、コンポーネント内の div のデータだけを変更する場合もあります。ネイティブ レンダリングを使用してビューを更新する場合は、コンポーネント全体を更新する必要があります。時間の無駄じゃないですか?

日常生活でこのような状況に遭遇した場合、すべてのピースを更新することはありません。パズルが完成した後、小さなピースの 1 つを交換する必要があるようなものです。ピースを見つけて直接交換するだけです。最初からやり直すことはありません。 Vue と React の開発者も同様に考えており、最適化するためにあらゆる可能な方法を試します。

人間の目には変更前と変更後の違いが一目でわかるので、その違いだけを更新すればいいのです。しかし、コンピューターはそれを一目で見ることはできません。違いを見つけて更新するまで、最初から素早く比較する必要があります。変更前と変更後を比較して相違点を見つけるプロセスを DOM Diff と呼びます。DOM Diff の DOM は仮想 DOM、つまり JavaScript オブジェクトです。1 つずつ比較して相違点を見つけた後、実際の DOM を部分的に更新します。

比較プロセス中に、仮想 DOM も仮想 DOM ツリーを形成します。DOM Diff の動作プロセスは、2 つの仮想 DOM ツリー上のオブジェクト ノードを比較することであり、具体的には各レイヤーの対応する位置を比較します。コンピュータは各レイヤーの対応する位置にある 2 つの仮想 DOM 要素のみを比較するため、2 つのツリー内の変更されたツリーのレイヤーに 1 つのノードのみが挿入された場合、ツリーの構造は変更されず、次の図に示すように、このレイヤーを比較するときに DOM Diff によって不整合な比較が発生します。

このレベルの仮想 DOM ノードは、DOM ノード自体を除いて Vue と React で完全に同じであるため、DOM Diff は比較時に対応する位置を 1 つずつしか比較できません。

1 対 1 の比較後、ノード タイプが同じであれば、ノードは再利用され、ノード内の異なるコンテンツのみが部分的に更新されます。上図に示すように、これが ul の下の li の仮想 DOM ノードである場合、1 つずつ比較してノード タイプが同じであることがわかった後、前のノードが再利用され、ノード内のコンテンツが変更されます。つまり、C は F に更新され、D は C に更新され、E は D に更新され、最後に E が挿入されます。

上記はノードを挿入する場合であり、その結果は効率の低下です。しかし、ノードを削除する場合、結果は効率だけではありません。

li 要素を削除するボタンをクリックすると、新しい仮想 DOM ツリーと古い仮想 DOM ツリーを比較するときに、ツリー内の各レイヤーの対応する位置に従って 1 つずつ比較されます。たとえば、削除後、[1,2,3] は [1,3] になります。最初の li と 2 番目の li を比較します。要素タイプが変更されていないことが判明した場合は、最初の li を再利用し、その中の li を再帰的に比較します。変更がないことが判明した場合は、再利用を続けます。 2 番目の li 要素を比較すると、それらも li 要素であることがわかるため、前の li が再利用され、2 のみが 3 に変更されます。

このとき、再利用された li にサブ要素があり、サブ要素が依存するデータが変更されていない場合、以前のサブコンポーネントが引き続き再利用され、次の図に示すように不整合が発生します。

2. 同じレイヤーの同じタイプの要素にキー属性を追加する

上記の DOM Diff アルゴリズムでは、2 つのツリーの同じレイヤーの対応する位置のみが比較されます。異なるレイヤー間の要素を比較する必要はありません。さらに、DOM Diff プロセスで、変更された仮想 DOM が以前の仮想 DOM と異なるタイプであることが判明した場合、以前の仮想 DOM はアンインストールされ、変更された要素ノードが再度追加されます。したがって、2 つのツリー内の同じレイヤーのノード タイプが同じである場合に上記の問題が発生し、レイヤーを追加または削除すると効率が低下したり、バグが発生したりします。

これは、v-for ループで同じタイプのラベル要素を生成すると発生します。ラベル ノードに対して何もしないと、バグが発生するリスクがあります。では、どうすればよいでしょうか。

答えは、同じレイヤーにある同じノード タイプのノードに一意のキー値を追加することです。このようにして、DOM Diff がペアワイズ比較を実行すると、対応する位置に従って比較するのではなく、同じキーを持つ 2 つの仮想 DOM が比較されます。

これにより、不整合な比較が回避され、比較の効率が大幅に向上し、バグのリスクが解決されます。

3. キーはインデックスの添え字値にはならない

配列やオブジェクトのインデックス値は一意であるため、キー属性の値としてインデックスを使用することがよくあります。これは問題なく、パフォーマンスの最適化などをもたらすと言う人もいますが、インデックス値を使用すると大きなバグのリスクが発生します。

これらのバグは、v-for ループ内のオブジェクトまたは項目が追加、削除されたり、順序が変更されたりしたときに発生します。

では、なぜインデックス添え字を使用できないのでしょうか?

実は、インデックスの添え字が使われたり使われなかったりするからです。追加や削除をすると、特定の要素のインデックスが変わるからです。例えば、[1,2,3]が[1,3]になった後、データ3に対応する元の添え字は2で、削除後はデータ3の添え字は1になります。DOM Diffを実行すると、等しいキー値に基づいてペアワイズ比較が実行されます。データ3に対応するノードは、まだ互いに対応していません。そのため、インデックスをキーとして使用すると、キーを設定しないのと同じ効果があります。

これが、インデックスをキーとして使用すべきではない理由です。

したがって、キー属性値は一意であり、変更されない必要があります。

上記は、vue における v-for のキー一意性についての詳細な説明です。vue における v-for のキー一意性についての詳細は、123WORDPRESS.COM の他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • Vue の v-for ループの主要属性に関する考慮事項のまとめ
  • vue v-for のループをトラバースするときにキー値エラーが発生する問題を解決する
  • Vueのキー属性を理解する方法の詳細な説明
  • Vue におけるキー値の重複問題

<<:  CentOS 7 でゲートウェイを変更して IP を設定する方法の例

>>:  MySQLのテーブル構造を変更する際に知っておきたいメタデータロックの詳しい解説

推薦する

CSS 評価効果の星の例

何?何のスターコートですか?さて、もっとわかりやすくするために写真を見てみましょう。 よく見ると、パ...

Elasticsearch を使用する際の一般的な問題の解決策

1. redis で使用すると Netty の起動競合が発生するため、***Application ...

Docker 構成 Alibaba Cloud イメージアクセラレーション プル実装

今日はdockerを使ってイメージをpullしたのですが、速度が悪くて見れず最後まで待ち続けました。...

CSS3 は反転可能なホバー効果を実現します

CSS3 は反転可能なホバー効果を実装します。具体的なコードは次のとおりです。 1.css /*基本...

AWSサーバーリソースを無料で使用する方法を教えます

AWS - Amazon のクラウド コンピューティング サービス プラットフォーム以前、AWS の...

JavaScriptの無限ループを検出して防止する方法の詳細な説明

目次序文for文の無限ループを修正while文の無限ループを修正要約する序文Js デッド ループはど...

Taobao ストアでズームインする効果は、スライドショーを使用する原理に似ています。

今日は、スライドを使用する原理に似た、Taobao のフロントエンドのマウス ズーム効果に慣れました...

Nexusプライベートサーバー構築原理とチュートリアル分析

1つ。 Nexus プライベート サーバーを構築する理由は何ですか?社内の開発メンバーは全員外部ネッ...

異なるページ間のJavaScriptデータ転送(URLパラメータ取得)

Web ページでは、あるページに情報を入力すると、別のページにジャンプし、入力した情報が別のページ...

MySQLデータ移行方法とツールの分析

この記事は主にMySQLデータ移行方法とツールの分析を紹介します。サンプルコードを通じて詳細に紹介さ...

Linuxのファイル操作の知識ポイントを詳しく解説

ファイル操作に関連するシステムコール作成するint creat(const char *ファイル名,...

EclipseでTomcatを作成する原理の詳細な説明

ローカルEclipse上にTomcatサーバーを作成する場合、 tomcaインストールディレクトリの...

MySQLの日付と時刻関数の使用の概要

この記事はMySQL 8.0に基づいていますこの記事では、日付と時刻の操作のための MySQL 関数...

MySQL 制約の超詳細な説明

目次MySQL 制約操作1. 非ヌル制約2. ユニーク制約3. 主キー制約4. 外部キー制約5. カ...

条件によるMysqlカウントの複数の実装方法を詳細に解説

最近、あるウェブサイトのバックエンドに一連の統計機能を追加していたのですが、条件によるカウントが必要...