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-8.0.17-winx64 のデプロイメント方法

1. 公式サイトからmysql-8.0.17-winx64をダウンロードし、Zipファイル形式を選択...

docker-swarm をベースにした継続的インテグレーション クラスタ サービスの構築の詳細な説明

序文この記事は私自身の製作過程の簡単な記録です。練習中に質問があれば、一緒に話し合うことができます。...

データ URI スキームを使用して Web ページに画像を埋め込む方法の紹介

データ URI スキームを使用すると、HTML、CSS、Javascript などで使用できるインラ...

Vue.jsは9グリッド画像表示モジュールを実装します

Vue.js を使用して、クリックしてズームできる 9 グリッドの画像表示モジュールを作成しました。...

Javascript サンプル プロジェクトでの虫眼鏡効果の実装プロセス

目次序文事例: JD.com の虫眼鏡効果の模倣オフセットシリーズクライアントシリーズスクロールシリ...

MySQL テーブルを返すとインデックスが無効になるケースの説明

導入MySQL InnoDB エンジンがレコードをクエリし、インデックス カバレッジを使用できない場...

nginxのアップストリーム設定と機能の詳細な説明

設定例 アップストリームバックエンド{ サーバー backend1.example.com 重み=5...

MySQL の起動時に InnoDB エンジンが無効になる問題の解決方法

問題を見つける今日、仕事中に、ローカル データベースから仮想マシン CentOS 6.6 上のデータ...

React の 3 つの主要属性における Ref の使用に関する詳細な説明

目次クラスコンポーネント機能コンポーネントインタビューのよくある質問: React における ref...

mysql データはどこに保存されますか?

MySQLデータベースの保存場所: 1. MySQLがMyISAMストレージエンジンを使用する場合...

MySQL で大量のデータ (数千万) を素早く削除するためのいくつかの実用的なソリューションの詳細な説明

著者は最近、仕事でパフォーマンスのボトルネックの問題に遭遇しました。MySQL テーブルには毎日約 ...

CentOS7 は yum を使用して mysql 8.0.12 をインストールします

この記事では、centos7にyumを使用してMySQL 8.0.12をインストールする詳細な手順を...

JSを使用して簡単な計算機を実装する

JSを使用して、参考用の簡単な計算機を完成させます。具体的な内容は次のとおりです。要件: 入力値は数...

Nginx を使用して rtmp ライブ サーバーを実行する方法

今回は、コンピューターや携帯電話用の rtmp ライブ ブロードキャスト サーバーを設定し、ライブ ...