平常在写 Vue 项目时,免不了要写一些 computed 来包装、计算一些数据。以方便我们使用。来看下 Vue3 中 computed 都做了什么。
export function computed<T>(getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>) {//初始化 getter、setter 和 副作用函数const c = _computed(getterOrOptions as any)//执行当前实例的副作用函数recordInstanceBoundEffect(c.effect)return c}
代码位置:packages/runtime-core/src/apiComputed.ts
// 第一种:const doubbleCount = computed(()=>num.value+1)// 第二种:const doubbleCount = computed({get: () => num.value + 1,set: val => num.value = val + 10})
export function computed(getterOrOptions) {//定义 getter 和 setterlet getterlet setter//先判断是否是函数?if (isFunction(getterOrOptions)) {//把我们写的 computed函数 赋值给 gettergetter = getterOrOptions//如果是开发环境赋值 一个包含错误信息的函数,如果是生产环境,赋值一个空函数setter = __DEV__? () => {console.warn(\\\'Write operation failed: computed value is readonly\\\')}: NOOP} else {//如果我们是以第二种方式传入的参数,那就直接赋值对应的 getter 和 settergetter = getterOrOptions.getsetter = getterOrOptions.set}//返回一个类,收集依赖、派发事件return new ComputedRefImpl(getter,setter,isFunction(getterOrOptions) || !getterOrOptions.set)}
代码文件:packages/reactivity/src/computed.ts
class ComputedRefImpl<T> {//缓存结果值private _value!: T//是不是脏数据?private _dirty = truepublic readonly effect: ReactiveEffect<T>public readonly __v_isRef = true;public readonly [ReactiveFlags.IS_READONLY]: booleanconstructor(getter: ComputedGetter<T>,private readonly _setter: ComputedSetter<T>,isReadonly: boolean) {//创建副作用函数this.effect = effect(getter, {//true 函数延迟执行lazy: true,//执行函数scheduler: () => {if (!this._dirty) {this._dirty = true//派发通知trigger(toRaw(this), TriggerOpTypes.SET, \\\'value\\\')}}})this[ReactiveFlags.IS_READONLY] = isReadonly}get value() {//如果是脏数据,则需要执行副作用函数if (this._dirty) {this._value = this.effect()this._dirty = false}track(toRaw(this), TrackOpTypes.GET, \\\'value\\\')return this._value}set value(newValue: T) {//设置新值this._setter(newValue)}}
代码文件:packages/reactivity/src/computed.ts
export function effect<T = any>(fn: () => T,options: ReactiveEffectOptions = EMPTY_OBJ): ReactiveEffect<T> {//是否是副作用函数if (isEffect(fn)) {fn = fn.raw}//创建副作用函数const effect = createReactiveEffect(fn, options)//是否立即执行if (!options.lazy) {effect()}return effect}
recordInstanceBoundEffect(c.effect)//方法export function recordInstanceBoundEffect(effect: ReactiveEffect,instance = currentInstance){if (instance) {;(instance.effects || (instance.effects = [])).push(effect)}}
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34580.html