Maison  >  Article  >  interface Web  >  Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

青灯夜游
青灯夜游avant
2022-01-22 15:05:003973parcourir

Pourquoi ne puis-je pas utiliser index comme clé lors de l'utilisation de v-for dans vue ? L'article suivant vous présentera la raison pour laquelle la valeur clé de v-for ne peut pas être indexée. J'espère qu'il vous sera utile !

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

Pourquoi la valeur clé de v-for ne peut-elle pas être indexée ?

Lorsque de nombreuses personnes parlent de cette question d'entretien courante, elles commencent immédiatement à parler de DOM virtuel et d'algorithme de comparaison. 虚拟DOMdiff算法 了。

讲这些没问题,但如果是我,一定先讲 v-for 的 key 值写成 index 会造成的问题,再讲原理。

曾经我写 v-for, key 值永远都是 index,直到有一天,我这么写造成了线上bug...

来看一下我的线上bug演示吧:

父组件代码
<Child
  v-for="(item, index) in list"
  :key="index"
  :count="item.count"
  :name="item.name"
  @delete="handleDelete(index)"
/>

list: [
    {
      count: 1,
      name: &#39;第1个元素&#39;
    },
    {
      count: 2,
      name: &#39;第2个元素&#39;
    },
    {
      count: 3,
      name: &#39;第3个元素&#39;
    }
  ]
  
handleDelete(index) {
  this.list.splice(index, 1)
},

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

如代码和gif演示,点击删除第2个元素,看上去似乎一切正常。

等一下,第三个元素的count值居然变成了2,wtf!!!

惊得我又去看了遍子组件的代码

子组件
<div>
  <span>{{ name }}</span>
  count值为:{{ innerCount }}
  <button @click="$emit(&#39;delete&#39;)">-</button>
</div>

props: {
  count: {
    type: Number,
    default: 0
  },
  name: {
    type: String,
    default: &#39;&#39;
  }
},
data() {
  return {
    innerCount: this.count
  } 
}

感觉也没什么不对的啊。

不信邪,我又多创建了点元素来删除,还试了下排序:

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

果然,不光删除元素有问题,排序也有问题。

把 key 值改成 item.name 再试一下。

<Child
  v-for="(item, index) in list"
  :key="item.name"
  :count="item.count"
  :name="item.name"
  @delete="handleDelete(index)"
/>

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

正常了。

这样看来,在 v-for 里把 key 值写成 index,非常危险啊。

在查阅了 vue 官方文档之后,我终于明白了原因:

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

不依赖子组件状态

子组件里有一行很关键的代码

data() {
  return {
    innerCount: this.count
  } 
}

子组件内部定义了 innerCount,这样子组件就有了自己的状态,按照官方文档的说明,这种情况下不能把 index 作为 key 值。

临时 DOM 状态

<div v-for="(item, index) in list1" :key="index">
  <input type="text" />
  <button @click="delClick(index)">删除</button>
</div>

Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?

删除了第2项,但是第3项在表单中的3变成了2,跟上面依赖子组件状态的例子是一样的。

总结

写列表渲染时, 依赖子组件状态或临时 DOM 状态的情况,如果有 删除、增加、排序这样的功能,不要把 index 作为 key。

事实上,写列表渲染时,永远不要把 index 做为 key,key 一定要是唯一标识。

至于原因,就要理解 diff

C'est bien d'en parler, mais si c'était moi, je parlerais d'abord des problèmes causés par l'écriture de la valeur clé de v-for comme index, puis je parlerais du principe.

J'ai déjà écrit v-for, et la valeur clé était toujours index. Jusqu'au jour où j'ai écrit ceci et provoqué un
    bug en ligne
  • ...
  • Jetons un coup d'œil à ma démonstration de bug en ligne :
  • rrreee

tels que le code et gif Démonstration, cliquez pour supprimer le deuxième élément, tout semble normal.

Attendez une minute, la valeur de comptage du troisième élément est en fait devenue 2, wtf ! ! !

J'ai été tellement choqué que j'ai regardé à nouveau le code du sous-composantrrreee

J'ai senti qu'il n'y avait rien de mal. 🎜🎜Je ne crois pas au mal, j'ai donc créé plus d'éléments à supprimer et essayé de trier : 🎜🎜Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?🎜🎜Effectivement, non seulement il y a un problème avec la suppression d'éléments, mais il y a aussi un problème avec le tri. 🎜🎜Changez la valeur clé en item.name et réessayez. 🎜rrreee🎜Pourquoi la valeur clé de la directive v-for ne peut-elle pas être indexée dans vue ?🎜🎜 C'est normal. 🎜🎜Il semble qu'il soit très dangereux d'écrire la valeur clé sous forme d'index dans v-for. 🎜🎜Après avoir consulté la documentation officielle de vue, j'ai enfin compris la raison : 🎜
🎜Lorsque Vue met à jour la liste d'éléments rendue à l'aide de v-for, elle utilise la "mise à jour sur place" par défaut stratégie. Si l'ordre des éléments de données est modifié, Vue ne déplacera pas les éléments DOM pour qu'ils correspondent à l'ordre des éléments de données, mais mettra à jour chaque élément en place et garantira qu'ils s'affichent correctement à chaque position d'index. 🎜
🎜Ce mode par défaut est efficace, mais 🎜ne convient qu'à la sortie de rendu de liste🎜 qui ne repose pas sur l'état du sous-composant ou sur l'état temporaire du DOM (par exemple : les valeurs d'entrée du formulaire). 🎜
🎜🎜Ne dépend pas de l'état du sous-composant🎜🎜🎜Il y a une ligne de code très critique dans le sous-composant🎜rrreee🎜L'innerCount est défini en interne dans le sous-composant, de sorte que le sous-composant a son propre état . Selon la documentation officielle, dans ce cas, l'index ne peut pas être utilisé comme valeur clé. 🎜🎜🎜État DOM temporaire🎜🎜rrreee🎜4 .gif🎜🎜Le 2ème élément est supprimé, mais le 3ème élément du formulaire devient 2, ce qui est le même que l'exemple ci-dessus qui repose sur l'état d'un sous-composant. 🎜

Résumé🎜🎜Lors du rendu d'une liste, cela dépend de l'état du sous-composant ou de l'état temporaire du DOM. S'il existe des fonctions telles que la suppression, l'ajout et le tri, ne le faites pas. utilisez l'index comme clé. 🎜🎜En fait, lors de l'écriture d'une liste pour le rendu, n'utilisez jamais d'index comme clé, la clé doit être un identifiant unique. 🎜🎜Quant à la raison, vous devez comprendre l'algorithme diff pour le comprendre. 🎜🎜Question à laquelle il faut répondre : 🎜🎜🎜Pourquoi la clé ne peut-elle pas être écrite sous la forme d'un nombre aléatoire ou d'un horodatage ? 🎜🎜Clé Pourquoi doit-il s'agir d'un identifiant unique ? 🎜🎜🎜Ne vous inquiétez pas, j'ai défini un drapeau pour écrire 100 articles liés aux problèmes de vue, je les analyserai lentement dans les articles suivants. 🎜🎜J'espère que ma série d'articles vue pourra vous être utile sur la route du front-end~🎜🎜[Recommandations associées : 🎜Tutoriel vidéo vue.js🎜]🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer