Vue3的ref和reactive

505 阅读2分钟

vue3refreactive是常用的两种变量声明方式,出于好奇以研究了下这两者的区别;

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来代理对象实现响应式,而mutableHandlersmutableCollectionHandlersreactiveMap三个方法都是对于对象的处理方法,感兴趣的可以去源码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的声明变量用途; 以上是个人在对vue3refreactive的一些拙见,欢迎探讨,如惹您不喜,请点击页签❎关闭即可;