vue3中的computed源码浅析

computed源码浅析

前面通过对reactive的阅读了解了一下响应式系统的概貌。现在开始对computed进行一定的了解,学习和理解这其中的思路。
在vue3中computed以composition api的形式暴露出来,因此可以直接通过computed方法作为入口去阅读理解其中的思路。

// computed.ts
// 函数重载
export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
export function computed<T>(
  options: WritableComputedOptions<T>
): WritableComputedRef<T>
export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>
) {
  // 这个方法内容很简单就是将传入的函数或者option对象,转换成computed的getter、setter
  let getter: ComputedGetter<T>
  let setter: ComputedSetter<T>

  if (isFunction(getterOrOptions)) {
    getter = getterOrOptions
    setter = __DEV__
      ? () => {
          console.warn('Write operation failed: computed value is readonly')
        }
      : NOOP
  } else {
    getter = getterOrOptions.get
    setter = getterOrOptions.set
  }
// 返回一个 ComputedRefImpl 实例作为计算属性
  return new ComputedRefImpl(
    getter,
    setter,
    isFunction(getterOrOptions) || !getterOrOptions.set
  ) as any
}

class ComputedRefImpl<T> {
  private _value!: T
  private _dirty = true

  public readonly effect: ReactiveEffect<T>
  // computed在vue3被定义为ref值,在模板或嵌套对象中使用时会自动解包
  public readonly __v_isRef = true;
  public readonly [ReactiveFlags.IS_READONLY]: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean
  ) {
    // 将getter传入effect函数,因为闭包的关系,后续在执行 this.effect 方法时会被激活成待收集依赖
    this.effect = effect(getter, {
      lazy: true,
      scheduler: () => {
        if (!this._dirty) {
          this._dirty = true
          // 触发computed的依赖
          trigger(toRaw(this), TriggerOpTypes.SET, 'value')
        }
      }
    })

    this[ReactiveFlags.IS_READONLY] = isReadonly
  }

  get value() {
    // 在get中调用this.effect来计算值
    // 惰性控制器,只有在所依赖数据改变后才会再次计算
    if (this._dirty) {
      this._value = this.effect()
      this._dirty = false
    }
    // 以computed实例为对象收集依赖,此处收集的是componentEffect,在组件挂载,更新时对vNode进行diff
    track(toRaw(this), TrackOpTypes.GET, 'value')
    return this._value
  }

  set value(newValue: T) {
    this._setter(newValue)
  }
}

computed中的主要逻辑就是这样。当调用computed api的时候会创建一个ComputedRefImpl实例,而在获取实例的值的时候。实例的getter会调用它的effect方法计算获取得到最终值。而在计算的过程中会因为get vue实例的数据触发数据的getter,此时就会在当前被获取的数据依赖收集器中收集此computed的effec。随后ComputedRefImpl实例会收集componentEffect(组件实例更新方法)作为依赖。

computed数据是具有缓存特性的,只有在所依赖的数据发生改变,触发了所依赖数据的setter。setter触发其收集的依赖,便会执行到ComputedRefImpl构造函数中传入effect的调度方法,触发此ComputedRefImpl实例所收集的所有依赖其中会包括componentEffect及其他依赖此计算属性的数据。

Created with Raphaël 2.2.0 computed component render computed getter VM data getter VM data change computed effect scheduler computed value computed 缓存数据 yes no
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值