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 !
Lorsque de nombreuses personnes parlent de cette question d'entretien courante, elles commencent immédiatement à parler de DOM virtuel
et d'algorithme de comparaison
. 虚拟DOM
和 diff算法
了。
讲这些没问题,但如果是我,一定先讲 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: '第1个元素' }, { count: 2, name: '第2个元素' }, { count: 3, name: '第3个元素' } ] handleDelete(index) { this.list.splice(index, 1) },
如代码和gif演示,点击删除第2个元素,看上去似乎一切正常。
等一下,第三个元素的count值居然变成了2,wtf!!!
惊得我又去看了遍子组件的代码
子组件 <div> <span>{{ name }}</span> count值为:{{ innerCount }} <button @click="$emit('delete')">-</button> </div> props: { count: { type: Number, default: 0 }, name: { type: String, default: '' } }, data() { return { innerCount: this.count } }
感觉也没什么不对的啊。
不信邪,我又多创建了点元素来删除,还试了下排序:
果然,不光删除元素有问题,排序也有问题。
把 key 值改成 item.name 再试一下。
<Child v-for="(item, index) in list" :key="item.name" :count="item.count" :name="item.name" @delete="handleDelete(index)" />
正常了。
这样看来,在 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>
删除了第2项,但是第3项在表单中的3变成了2,跟上面依赖子组件状态的例子是一样的。
写列表渲染时, 依赖子组件状态或临时 DOM 状态的情况,如果有 删除、增加、排序这样的功能,不要把 index 作为 key。
事实上,写列表渲染时,永远不要把 index 做为 key,key 一定要是唯一标识。
至于原因,就要理解 diff
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 : 🎜🎜🎜🎜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🎜🎜🎜 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🎜🎜🎜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. 🎜
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!