问题背景
是在vue2项目升级vue3项目中遇到的,因为升级项目并没有使用vue的Composition api 而是使用Options api,所有复杂类型变量默认使用reactive进行响应式,问题也是从这出现的
- 对象数组中,使用索引值更改数据,数据变化了页面没有变化
- 类似代码 - options api使用的是this指针方式,但是问题是一样的
javascriptarr1:[ { "name": "test", "name2": "test2", "name3": "test3", }, { "name": "test", "name2": "test2", "name3": "test3", } ] }) arr["arr1"][0] = {"name": "test11","name2": "test22","name3": "test33",}
这个时候我们从vue3的源代码入手,分析原因,具体只需要看proxy 的 get方法
源代码地址 packages\reactivity\src\baseHandlers.ts
有个BaseReactiveHandler方法

当我们触发get方法时,如果还是复杂类型,需要在调用reactive将其转化成响应式,所以Vue的依赖收集是"按需"的,具有一种懒惰性质,层级较深的复杂类型数据不是在声明式就被全部转化成响应式,而是在获取时逐层转化的
这个时候我们回看我们的问题,当我们执行arr["arr1"][0] = {"name": "test11","name2": "test22","name3": "test33",}的时候,只触发了arr["arr1"],但是再往下层级的并没有被转化成响应式,所以此时我们可以这样去解决
javascript"test11","name2": "test22","name3": "test33",} arr["arr1"] = newArr[0]
- 解构失去响应式
javascriptconst test = reactive({ arr: { name: '111'} }) // 解构会失去响应性! const { arr } = test // 修改 user 不会触发界面更新 arr.name = '李四' //界面不更新 //解决方案 // 1、 const { arr } = toRefs(test) // 2、尽量不要解构响应式数据
- Object新增属性不响应
javascriptconst test = reactive({ arr: { name: '111'} }) // 修改 user 不会触发界面更新 test.arr.age= 22 //界面不更新 // 解决方法 使用 Object.assign Object.assign(test.arr, { age: 22 }) // 触发更新
总结
所以在vue3 开发中,如果使用options api方式,就需要尽量注意多层嵌套对象,如果使用Composition api,尽量使用 ref 去定义变量,并且针对嵌套层级较深的变量最好使用ShallowRef ShallowReactive 用于优化深层嵌套对象的性能问题