今天去面试被问了这个问题,问我平时ref用的多还是reactive用的多,还问了将ref和reactive分别赋值给一个对象有什么区别,当时就蒙了,现在回来复盘,其实也没什么区别,无非就是一个要用.value访问,一个不用罢了,在实际使用上还是建议统一用ref
什么是ref与reactive
ref与reactive都是Vue3中新增的组合式API函数,用于响应式数据的处理
1. ref
ref函数可以用于将一个普通的数据类型转换成响应式数据。ref返回一个包含value属性的对象
通过修改value属性的值,可以触发组件更新(注意组件更新不会立即执行DOM更新, 而是将更新放入一个队列,等待当前事件循环结束后统一处理)
2. reactive
reactive用于将一个普通对象转换成响应式数据。reactive返回一个响应式的Proxy对象,通过修改该对象的属性值,可以触发组件更新
二者区别及赋值对象区别:
-
ref返回一个包含value属性的对象,而reactive返回一个响应式的Proxy对象
-
在使用上,ref更方便一些,使用起来更简单直观。而reactive比较灵活,可以将任意对象转换成响应式数据,并且可以进行深层次的响应式处理
在 Vue 3 中,ref
和 reactive
都可以创建响应式数据,但当它们被赋值给对象属性时,行为有重要区别:
1. ref
赋值给对象
const count = ref(0)
const obj = {
count: count // 或简写为 count
}
特点:
-
对象属性会保持
ref
的引用(实际存储的是ref
对象) -
访问时需要
obj.count.value,而obj.count访问到的则是count对象
-
在template模板中自动解包(无需
.value
) -
响应性保持:修改
count.value
或obj.count.value
都会触发更新
2. reactive
赋值给对象
const state = reactive({ num: 1 })
const obj = {
state: state
}
特点:
-
对象属性直接引用
reactive
的响应式代理 -
访问时不需要
.value
:obj.state.num
-
响应性保持:修改
obj.state.num
会触发更新
适用场景 :
1. ref赋值对象适用于操作基本数据类型
2. 而reactive适合操作对象/数组等复杂数据结构,并且能够直接操作属性或元素
响应式丢失的问题
响应式连接丢失
由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
解构丢失数据响应式:
当我们将响应式对象的原始类型属性解构出来时,或者将该属性传递给函数时,我们将丢失响应性连接:
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 但是不会影响原始的 state,ref也是如此
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
Function(state.count)
// 传入state对象,在函数里调用state.count则不会丢失响应式
Function(state)
ref 的解包
将一个 ref 赋值给一个 reactive
属性时,该 ref 会被自动解包:
const count = ref(1)
const obj = reactive({ count })
// ref 会被解包
console.log(obj.count === count.value) // true
// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
详情请见Vue3文档:响应式 API:核心 | Vue.js
ref实现原理
详细底层代码在Github上:core/packages/reactivity/src/ref.ts at main · vuejs/core · GitHub
结论:ref()
在背后就是使用的 reactive()
,你可以把 ref()
简单看成:
const myRef = reactive({ value: "I'm ref!" })
myRef.value // "I'm ref!"
myRef.value = 'Changed'
myRef.value // "Changed"