List列表数据不更新是怎么回事?
我用 Vue 写了个 List 列表,数据是从父组件传进来的 props,但当我修改了父组件的数据后,子组件的列表没跟着变,明明控制台打印出来 props 已经变了啊。
我试过在子组件里加 watch 监听 props,也试过直接用 computed 返回 props 的值,都不行。是不是我哪里写错了?
这是我的子组件关键代码:
<template>
<div>
<div v-for="item in listData" :key="item.id">{{ item.name }}</div>
</div>
</template>
<script>
export default {
props: ['listData']
}
</script>
解决这个问题的一个常见方法是在父组件中使用浅拷贝或者深拷贝来确保每次传递的都是一个新的引用。你可以试试用
Object.assign或者扩展运算符...来优化一下。比如这样改父组件的传递方式:
这样可以确保每次传递给子组件的都是一个新的引用,子组件就能检测到变化并重新渲染了。
如果还是不行,检查一下有没有其他地方影响了数据的响应式更新,有时候 Vue 的响应式系统在处理复杂的数据结构时可能会有坑。
Vue2 的响应式是有局限性的,不是所有数据修改都能触发更新。你说控制台打印 props 已经变了,但这不代表 Vue 渲染层检测到了这个变化。
父组件里你是不是直接这样改了数据?
// 这样改不会触发更新
this.listData[index] = newItem
this.listData[0].name = '新名字'
或者这样?
this.listData.forEach(item => {
item.xxx = newValue
})
Vue2 对数组和对象的属性修改检测不到这种写法。官方文档里专门提到了数组的注意事项,必须用特定方法才能触发响应式。
解决办法很简单,别直接修改原数组,用下面这些方式:
// 数组替换
this.listData = [...this.listData]
// 或者用 splice
this.listData.splice(index, 1, newItem)
// 或者用 $set
this.$set(this.listData, index, newItem)
对象也是同理,别直接
obj.key = value,用this.$set(obj, 'key', value)或者直接整个对象替换掉。你可以检查一下父组件那边是怎么改数据的,大概率就是这个问题。