Api介绍
computed函数
computed函数存在两个接口实现。
- computed函数接收一个getter函数,返回一个只读的ref对象。
- computed函数接收一个getter函数和一个setter函数,返回一个可写的ref对象。
ts
/**
* Takes a getter function and returns a readonly reactive ref object for the
* returned value from the getter. It can also take an object with get and set
* functions to create a writable ref object.
*
* @example
* ```js
* // Creating a readonly computed ref:
* const count = ref(1)
* const plusOne = computed(() => count.value + 1)
*
* console.log(plusOne.value) // 2
* plusOne.value++ // error
* ```
*
* ```js
* // Creating a writable computed ref:
* const count = ref(1)
* const plusOne = computed({
* get: () => count.value + 1,
* set: (val) => {
* count.value = val - 1
* }
* })
*
* plusOne.value = 1
* console.log(count.value) // 0
* ```
*
* @param getter - Function that produces the next value.
* @param debugOptions - For debugging. See {@link https://vuejs.org/guide/extras/reactivity-in-depth.html#computed-debugging}.
* @see {@link https://vuejs.org/api/reactivity-core.html#computed}
*/
export function computed<T>(
getter: ComputedGetter<T>,
debugOptions?: DebuggerOptions,
): ComputedRef<T>
export function computed<T, S = T>(
options: WritableComputedOptions<T, S>,
debugOptions?: DebuggerOptions,
): WritableComputedRef<T, S>
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions,
isSSR = false,
) {
let getter: ComputedGetter<T>
let setter: ComputedSetter<T> | undefined
if (isFunction(getterOrOptions)) {
getter = getterOrOptions
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}
const cRef = new ComputedRefImpl(getter, setter, isSSR)
if (__DEV__ && debugOptions && !isSSR) {
cRef.onTrack = debugOptions.onTrack
cRef.onTrigger = debugOptions.onTrigger
}
return cRef as any
}
computed 代理对象实现
ts
/**
* @private exported by @vue/reactivity for Vue core use, but not exported from
* the main vue package
*/
export class ComputedRefImpl<T = any> implements Subscriber {
/**
* @internal
*/
_value: any = undefined
/**
* @internal
*/
// 初始化依赖集合对象,用于追踪依赖关系
readonly dep: Dep = new Dep(this)
/**
* @internal
*/
readonly __v_isRef = true
// TODO isolatedDeclarations ReactiveFlags.IS_REF
/**
* @internal
*/
readonly __v_isReadonly: boolean
// TODO isolatedDeclarations ReactiveFlags.IS_READONLY
// A computed is also a subscriber that tracks other deps
/**
* @internal
*/
deps?: Link = undefined
/**
* @internal
*/
depsTail?: Link = undefined
/**
* @internal
*/
flags: EffectFlags = EffectFlags.DIRTY
/**
* @internal
*/
globalVersion: number = globalVersion - 1
/**
* @internal
*/
isSSR: boolean
/**
* @internal
*/
next?: Subscriber = undefined
// for backwards compat
effect: this = this
// dev only
onTrack?: (event: DebuggerEvent) => void
// dev only
onTrigger?: (event: DebuggerEvent) => void
/**
* Dev only
* @internal
*/
_warnRecursive?: boolean
constructor(
public fn: ComputedGetter<T>,
private readonly setter: ComputedSetter<T> | undefined,
isSSR: boolean,
) {
// 当没有传入setter时,说明这是一个只读的computedRef
this[ReactiveFlags.IS_READONLY] = !setter
this.isSSR = isSSR
}
/**
* @internal
*/
notify(): true | void {
this.flags |= EffectFlags.DIRTY
if (
!(this.flags & EffectFlags.NOTIFIED) &&
// avoid infinite self recursion
activeSub !== this
) {
batch(this, true)
return true
} else if (__DEV__) {
// TODO warn
}
}
get value(): T {
const link = __DEV__
? this.dep.track({
target: this,
type: TrackOpTypes.GET,
key: 'value',
})
: this.dep.track()
refreshComputed(this)
// sync version after evaluation
if (link) {
link.version = this.dep.version
}
return this._value
}
set value(newValue) {
if (this.setter) {
this.setter(newValue)
} else if (__DEV__) {
warn('Write operation failed: computed value is readonly')
}
}
}