Vue3源码【一】—— ref&reactive响应式原理及简单实现

响应式 ref、reactive


源码地址:https://github.com/vuejs/core

首先还是从最开始学的ref的源码看起,他的路径在packages/reactivity/src/ref.ts,这里看源码分析就直接将源码执行的步骤给他粘贴出来了哈。首先我们看一下ref是怎么创建的

1、创建Ref

// 第一步,我们还是直接到ref关键字,可以看到这个,这个就是我们使用的ref()用来创建响应式对象的关键。他会去调用createRef,并且第二个指定了false
export function ref(value?: unknown) {
   
  return createRef(value, false);
}

// 第二步,顺着上面往下执行,会调用createRef,这个时候我们知道第二个参数false是指什么了,也就是shallow,这个时候可能会想到shallowRef?
// shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。那默认创建的这个ref指定了false,那要是shallowRef调用createRef创建Ref是不是就是指定的true呢?这个我们后面再看
// 在这里先判断isRef,这个很好理解,就是看入参的是不是一个ref了,
function createRef(rawValue: unknown, shallow: boolean) {
   
  if (isRef(rawValue)) {
   
    return rawValue;
  }
  return new RefImpl(rawValue, shallow);
}

// 第三步,直接看RefImpl,这个就是将一个变量给包装成Ref(响应式对象)
// 这里看构造函数,先都会判断一下shallow是真还是假,响应式对象入的是false,他数据包装会变成toRaw和toReactive
// 在这里我们知道reactive是用来包对象类型的,这里ref创建本质上也是对调reactive的方法,同时我们也知道了为什么使用ref包的对象要加一个.value取取值赋值
// 看一下shallowRef的构造,果然就是return createRef(value, true),这样也解释了shallowRef为什么处理的是基本数据类型
// 看一下isRef方法,return !!(r && r.__v_isRef === true) r就是RefImpl实例对象,用来判断的也就是这个r.__v_isRef === true 是否为ref
class RefImpl<T> {
   
  private _value: T;
  private _rawValue: T;

  public dep?: Dep = undefined;
  public readonly;
  __v_isRef = true;

  constructor(
    value: T,
    public readonly __v_isShallow: boolean
  ) {
   
    this._rawValue = __v_isShallow ? value : toRaw(value);
    this._value = __v_isShallow ? value : toReactive(value);
  }

  get value() {
   
    trackRefValue(this);
    return this._value;
  }

  set value(newVal) {
   
    const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
    newVal = useDirectValue ? newVal : toRaw(newVal);
    if (hasChanged(newVal, this._rawValue)) {
   
      this._rawValue = newVal;
      this._value = useDirectValue ? newVal : toReactive(newVal);
      triggerRefValue(this, DirtyLevels.Dirty, newVal);
    }
  }
}

2、依赖收集

我们先看一个他的get
value是这么拿到值的,也就是trackRefValue方法。首先他在处理的时候先通过toRaw转成原始对象,从这里往下的源码就做了一些删减,有一些对数据进行异常判断处理的这里就都不展示了,主要看执行逻辑

export function trackRefValue(ref: RefBase<any>) {
   
  // true && undefined
  if (shouldTrack && activeEffect) {
   
    // 先转成原始对象
    ref = toRaw(ref)
    trackEffect(
      activeEffect,
      // ref.dep 不存在就调用createDep赋值给ref.dep  本质上是一个Map
      (ref.dep ??= createDep(
        () => (ref.dep = undefined),
        ref instanceof ComputedRefImpl ? ref : undefined,
      )),
      void 0,
    )
  }
}

重要的还是这个trackEffect方法。简单来说就是将里面的所有属性都给收集到一个map当中,通过这个map来做统一的依赖控制。后面取值也会从Map当中取值。

export function trackEffect(
  effect: ReactiveEffect,
  dep: Dep,
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
   
  // 默认值 eff._trackId = 0
  if (dep.get(effect) !== effect._trackId) {
   
    dep.set(effect, effect._trackId);
    

你可能感兴趣的:(#,vue3,javascript,前端,vue.js)