v-for循环key用index的bug

1,196 阅读2分钟

近期公司项目中出现了一个bug,场景为:我们使用列表list作为循环遍历一个子组件,key值用的list的index下标,list中的每一项item作为props属性传入子组件中,如图。

在子组件中,我们以item内的值为判断标准定义了一个组件的data属性,如图。

组件如图:

然后我们在父组件中对list数组进行筛选操作,筛选过后,list长度变短,内容顺序自然变化,我们遍历的子组件顺序也相应发生变化。

这时bug出现了,我们第三个子组件经过筛选后,来到了第一位,这时它data中由item内值作为判断标准的isChange属性,竟然变成了筛选前第一个组件的isChange属性,子1的isChange是true,子3的isChange是false,筛选后子3的isChange变成了true,bug形成。

然后就找问题,虽然通过筛选改变了list数组,但传入子组件的数据是正确的,这样按理说,子组件data中数据是依托于传入数据,不会变才对,为什么第三个组件顺序变成第一位时,data里的数据变了呢?

研究其原因,发现是diff算法搞的鬼,Diff算法是计算出 Virtual DOM中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。

如下图,更新后的子组件3来到了子组件1的位置,它的key值变成0,所以它将跟旧的中相同index也就是子组件1做比较,比较后diff算法只更改了props接收的item数据,因为data是个带返回值的函数,而此操作只是局部更新,并没有重新加载组件,所以data函数没有重新执行,而是沿用了原先index为0的data返回的数据,所以出现了该问题。

解决方法:使用item中的id作为key值进行遍历,问题解决。

tips:大家开发过程中使用v-for循环数组时,避免像俺一样图省事用index下标作为key值,推荐用item中的唯一属性作为key值,比如id这类值。加油~