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のテーブル構造を変更する際に知っておきたいメタデータロックの詳しい解説

推薦する

MySQL の日付型の単一行関数コードの詳細な説明

MySQL の日付型単一行関数: CURDATE()またはCURRENT_DATE()は現在の日付を...

VScode設定のリモートデバッグLinuxプログラムの問題を解決する

VScode リモートデバッグ Linux プログラムの問題について見てみましょう。具体的な内容は以...

Vue カードスタイルのクリックして切り替える画像コンポーネントの使用方法の詳細な説明

この記事では、vueカードスタイルのクリックして切り替える画像コンポーネントを参考までに紹介します。...

一般的な Dockerfile コマンドの使用方法の紹介

目次01 CM 02 エントリーポイント03 ワークディレクトリ04 環境05 ユーザー06巻07 ...

MySQL の binlog_format モードと設定の詳細な分析

MySQL レプリケーションには、SQL ステートメント ベースのレプリケーション (SBR)、行ベ...

ウェブページ作成時のHTMLタグの使用に注意してください

HTML はプレゼンテーションからコンテンツへの移行を試みており、コンテンツの意味(HTML) とプ...

MySQL 8.0 で列を素早く追加する方法

序文: MySQL 8.0 では高速な列追加がサポートされ、数秒で大きなテーブルにフィールドを追加で...

JavaScript が Jingdong の虫眼鏡効果を模倣

この記事では、Jingdongの虫眼鏡効果を実現するためのJavaScriptの具体的なコードを紹介...

MySQL データベースで機密データの暗号化と復号化を実装する方法

目次1. 準備2. MySQL暗号化関数方式2.1 MySQL 暗号化2.2 MYSQL 復号化3....

Docker での Redis の最も詳細なインストールと構成 (画像とテキスト付き)

1. Dockerに適したRedisのバージョンを見つけるdocker hubで見つけることができ...

MYSQLクエリデータの結果に自動的に番号を付ける方法

序文実際、クエリ中に結果に番号が付けられるこのような状況に遭遇したことは一度もありません。同僚が転職...

JavaScript インタビュー: 配列の平坦化メソッドを実装する方法

目次1 配列のフラット化とは何ですか? 2 JS標準ライブラリの配列フラット化メソッド3 フラットメ...

列名を知らなくてもMySQLインジェクションを詳細に解説

序文最近、穴を掘ってスペースを作っているだけなので、心が空っぽになっているように感じます。テクノロジ...

jQuery をベースにリスト ループ スクロールを実装するためのヒント (超簡単)

良いアイデアを見つけたので記録しました。私は以前、スクロール効果を実現するためにjQueryを使用し...

Centos6にMysql5.7をインストールする方法

環境セントロス6.6 MySQL 5.7インストールシステムがインストールされている場合は、まずアン...