使用ref声明多层嵌套对象及变化检测
- 声明:使用
ref
声明多层嵌套对象时,ref
会将传入的值包裹成一个带有.value
属性的对象。例如:
import { ref } from 'vue';
const nestedObject = ref({
a: {
b: {
c: 1
}
}
});
- 变化检测:当修改深层对象属性时,如
nestedObject.value.a.b.c = 2
,由于ref
包裹的对象本身是一个响应式引用,Vue通过Object.defineProperty
的getter
和setter
来追踪对.value
的访问和修改。当.value
被修改,Vue能够检测到引用的变化,进而触发视图更新。因为整个nestedObject.value
被视为一个整体,任何对其内部属性的更改都会导致整个对象引用的变化检测。
使用reactive声明多层嵌套对象及变化检测
- 声明:使用
reactive
声明多层嵌套对象时,reactive
会直接将传入的对象转换为响应式对象。例如:
import { reactive } from 'vue';
const nestedObject = reactive({
a: {
b: {
c: 1
}
}
});
- 变化检测:Vue利用
Object.defineProperty
对对象的每个属性进行劫持,为每个属性设置getter
和setter
。当访问或修改深层对象属性nestedObject.a.b.c = 2
时,setter
会被触发,Vue的依赖收集机制能够检测到该属性的变化,并通知相关的Watcher进行视图更新。Vue会精准地检测到具体属性的变化,而不是像ref
那样基于整个对象引用的变化。
检测机制不同点
- ref:基于对象引用的变化检测,修改深层属性时,因为整体对象引用通过
.value
被修改,从而触发更新。它是对整个值的包裹,检测粒度相对较粗。
- reactive:基于对对象每个属性的劫持,通过
getter
和setter
精准检测到具体属性的变化,检测粒度更细。
性能优化不同点
- ref:由于是基于对象引用变化,当深层属性变化时,可能会导致不必要的重新渲染,因为整个对象引用变化会使Vue认为整个对象都改变了,即便只是深层的一个小属性改变。但在一些简单场景或者对性能要求不高的场景下,使用简单,代码逻辑清晰。
- reactive:因为能精准检测到具体属性变化,在大型复杂对象且频繁修改深层属性的场景下,性能更优。Vue可以只针对变化的属性进行更新,减少不必要的重新渲染。但在嵌套层级过深时,依赖收集和更新的开销也会增大,需要合理设计数据结构来优化。