当我们在使用Vue3.x的时候,ref和reactive这两个API很常用,但是也经常容易搞混。这篇攻略将介绍ref和 reactive的区别,并且通过源码分析来更加深刻理解这两者之间的差异。
1. reactive
reactive
是用于将对象转为响应式的API。我们一般使用这个API来将普通的对象转成可以响应式地监听的对象。使用方法如下所示:
import { reactive } from 'vue'
const reactiveObject = reactive({
count: 1
})
从上面的代码中,我们可以看出,将对象传给 reactive()
后会返回一个通过 Proxy
实现的响应式对象,而这个响应式对象可以监听到它自身属性的变化。
2. ref
ref
是用来定义一个响应式数据的API。如果我们的目标只是一个基本类型的变量或者只需要进行单向绑定,则可以选择使用ref
。下面是使用ref
的例子:
import { ref } from 'vue'
const count = ref(1)
从上面代码中,我们可以看出,ref
会接收一个基本类型的数据,例如数值、字符串等,然后返回一个响应式对象。这个响应式对象有一个 .value
的属性,通过 .value
属性获取到的就是我们传入ref()
的值。
3. ref和reactive的区别
- ref是针对基本类型变量的响应式处理,reactive是针对对象类型的响应式处理。
- ref返回的对象具有 .value 属性,而reactive返回整个对象。
- ref可以修改基本类型的值,而reactive不能直接修改对象属性的值,只能使用
.value
或者toRefs
来修改。
下面通过源代码来进一步理解这两者的区别。
import { ref, reactive } from 'vue'
const stateA = {
count1: ref(1),
count2: 2,
countObj: reactive({
count: 3
})
}
stateA.count1++ // 可以直接修改数值类型
stateA.count2++ // 修改会报错,需要使用reactive
stateA.countObj.count++ // 可以直接修改reactive对象属性
通过上面这段代码可以看出,在对象中,对象属性的直接修改仅仅适用于reactive对象,而针对基本类型的变量则可以使用ref。至于为什么可以这样,我们可以通过源码来分析。
4. 源码分析
首先我们来看ref
的源码:
export function ref(value) {
// 对基本类型的值进行处理
return createRef(value)
}
function createRef(rawValue, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
const value = shallow ? rawValue : convert(rawValue)
const runner = effect(() => {
if (!isRef(runner)) {
runner.value = value.value
}
}, {
lazy: true,
scheduler: shallow ? () => {} : triggerRef
})
const ref = {
_isRef: true,
get value() {
trackRefValue(ref)
return value
},
set value(newVal) {
if (hasChanged(toRaw(newVal), rawValue)) {
rawValue = newVal
value.value = shallow ? newVal : convert(newVal).value
triggerRef(ref)
}
}
}
return ref
}
从源码中可以看到,ref
是通过 createRef
实现的,这个函数是设置基础类型数据的响应式的。
然后我们看reactive
的源码:
export function reactive(target) {
if (target && target._isReadonly) {
return target
}
// 如果target已经被处理过为响应式的,则直接返回target
if (reactiveMap.has(target)) {
return reactiveMap.get(target)
}
// 如果target是ref,则直接返回.value对应的响应式对象
if (target && target.__v_isRef) {
return reactive(target.value)
}
const observed = new Proxy(target, baseHandlers)
reactiveMap.set(target, observed)
return observed
}
从源码中可以看到,reactive
是通过创建新的 Proxy
对象来实现对象的响应式的。当 get
和 set
对象属性时,替换成监听 track
和 trigger
。
基于这些源代码,我们可以得出ref
和reactive
的差异:
- ref创建了一个对象,并通过这个对象的getter和setter来监听反应式数据的变化;
- Reactive将一个对象变为响应式对象,并将其对象的所有属性都转为getter和setter来监听反应式数据的变化;
这就是ref和reactive之间的区别。对于基础类型数据,可以使用ref
进行设置响应式;对于对象类型数据可以使用reactive
设置响应式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一步步从Vue3.x源码上理解ref和reactive的区别 - Python技术站