在Vue中为什么v-for一定要加key
如果你已经很熟悉Vue,一定也会很熟悉v-for指令。如果用过其他的前端框架的话,它们也都提供了在HTML模板中循环数据标记的方法。今天这篇文章让我们搞明白为什么key属性对于v-for这么重要。我在刚开始写Vue时,也很少去写key 属性,因为它也不是必需的,不写也不会报错,也不会耽误数据渲染。但当项目中配了ESLint的规则,必需要写key时,我就统一的都把index索引作为key,然后接着开
如果你已经很熟悉Vue,一定也会很熟悉v-for
指令。如果用过其他的前端框架的话,它们也都提供了在HTML模板中循环数据标记的方法。今天这篇文章让我们搞明白为什么key
属性对于v-for
这么重要。
我在刚开始写Vue时,也很少去写key 属性,因为它也不是必需的,不写也不会报错,也不会耽误数据渲染。但当项目中配了ESLint的规则,必需要写key时,我就统一的都把index
索引作为key
,然后接着开发,就像下面这样:
<h1 v-for="(item, index) in list" :key="index">{{ item.title }}</h1>
术语解读
那为什么我们需要在v-for
循环中加key
属性呢?
其实是因为Vue可以通过key
这种方式来观察数组或者对象中的数据哪些正发生变化。v-for
默认是通过index索引来追踪变化,所以上面我通过将index作为索引的做法是多余的,尽管它解决了ESLint的错误。通过追踪index索引,Vue观测列表中的项目的顺序变化,并在顺序发生变化时,就地修改每个项目。Vue文档中指出,“这个默认的模式是高效的”,但也指出并不适合所有的情况。
像Vue文档所说的那样,我们要尽可能使用数据的唯一ID来做每个元素的key,这样 Vue 可以更准确地追踪数组中项目的更改并更新组件状态,并且能够重用和重新排序现有组件,而不必重新渲染整个循环。
举例说明
上面说了那么多可能比较官方,还是不容易理解,下面我们通过一个例子来展示key
属性的重要性。
假设我们有一个图书列表,然后有一个book-detail
组件用来展示书的名称,和购买按钮,然后循环这个book-detail
组件
book-detail
组件代码如下:
<div class="book">
<h1>{{ book.title }}</h1>
<div v-if="isCheckedOut" class="label">立即购买</div>
</div>
组件展示这本书的书名,以及这本书是否能被购买。
组件的JavaScript部分:
export default {
name: 'Book',
props: ['book'],
data() {
return {
isCheckedOut: null
}
},
mounted() {
this.checkBookStatus(this.book.id);
},
methods: {
checkBookStatus() {
axios.get(`/book-status/${this.book.id}`)
.then(res => {
this.isCheckedOut = res.data.isCheckedOut;
})
}
}
}
我们通过props将书的信息传入,然后假设我们需要单独调用接口去查询这本书的状态,是否可以被购买。
然后循环出图书列表:
<book-detail v-for="(book, index) in books" :key="index" :book="book"></book-detail>
完整的在线例子地址:https://codepen.io/cmdfas-the-bashful/pen/yLoEmJq
这看起来并没有什么问题,在页面展示上也没有什么问题。到这里就结束了?并没有
假设用户可以向系统添加一本新书,并要求添加到列表顶部,而不是底部。如果添加到底部,不会有什么问题,因为index索引仍然是新的值,如果添加到列表顶部,那新加到顶部元素的索引将会之前第一本书的索引也就是0,依次类推,只有最后一本的索引为新索引。
能看出这里可能存在什么问题吗?如果Vue没有正确地将第一个索引追踪为新索引,那该组件永远不会重新挂载,所以checkBookStatus
永远不会更新图书的状态,相反,isCheckedOut
的值将是前一本书的值。
那么要解决这个问题最简单的方式就是设置唯一的key值,我将book.id
作为key值,Vue 将能够正确跟踪更改并将新组件添加到顶部并重新排序其余组件。
<book-detail v-for="(book, index) in books" :key="book.id" :book="book"></book-detail>
总结
明白了其中的原理,我们可以根据场景去选择使用v-for和key,如果只是将数据插入到数组末尾,或者只是简单的列表,那使用索引不会产生什么问题,因为没有排序,Vue可以正确的追踪到新的索引。这是一种很好的处理方式(也是 Vue 使用的默认方式)。
但是,当你带有props的组件中拥有组件自己的状态时,或者不只是在末尾添加内容的方式改变列表时,一定要使用唯一的id。
同样,有关 v-for 中使用的更多有用信息,建议查看 Vue 官方文档。
更多推荐
所有评论(0)