在vue3中ref和reactive是常用的两种变量声明方式,出于好奇以研究了下这两者的区别;
reactive
export function reactive<T extends object>(target: T): Reactive<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap,
)
}
从上面的官方源码可以看出,reactive的入参类型是已经限制死了的,必须是object,传入对象后reactive函数又对传入对象做了二次处理,由于在vue3中使用proxy来代理对象实现响应式,而mutableHandlers、mutableCollectionHandlers、reactiveMap三个方法都是对于对象的处理方法,感兴趣的可以去源码core/packages/reactivity/src/reactive.ts去看看,所以如果我这样写的话:
const data = reactive({});
const res = ()=>{
axios.post().then(()=>{
data = res
})
}
就发现一个很神奇的情况,data他无法响应式处理了,这个其实从上面reactive应该很容易看出来是因为没有了poxy代理了,就好比我们拿了个箱子往箱子里放了些东西,然后对这个箱子做了一些修改让我从里面取放东西更加方便,后面当你要装东西时,又重新拿了个一摸一样的箱子往里面放东西,虽然这个箱子和之前的箱子一摸一样,但我们之前对箱子的修改已经不在了,所以要么你只能从新修改才能达到和之前箱子一样的效果,放到代码中就是使用reactive声明的变量我们只能去修改里面的键值,不能修改变量的指针地址,也就是不能修改原对象,例如:
const data = reactive({value:1});
data.value=2;
const arr = reactive([]);
arr.push(1);
arr.push([...newarr]);
arr.concat(newarr);
ref
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
return createRef(value, false)
}
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
//这里做了删减,详细的请看官网
private _value: T
constructor(
value: T,
public readonly __v_isShallow: boolean,
) {
this._value = __v_isShallow ? value : toReactive(value)
}
set value(newVal) {
const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
const oldVal = this._rawValue
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, DirtyLevels.Dirty, newVal, oldVal)
}
}
}
从源码中可以看出,ref首先在参数限制上没有限制,其次在ref的创建过程中,可以看到,在首次创建和值改变时都会通过toReactive来进行处理成响应式,这样一来就可能出现异步或者响应延迟的问题,所以个人觉得ref最好时用来声明固定值、数字、字符串、布尔值;当然这仅仅只是ref的声明变量用途;
以上是个人在对vue3的ref和reactive的一些拙见,欢迎探讨,如惹您不喜,请点击页签❎关闭即可;