computed
计算属性,当computed内所依赖的数据发生变化时,computed会重新执行计算,如果没发生改变,computed会将之前计算后缓存的结果返回。
接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
computed接收参数类型
// 只读
function computed<T>(
getter: () => T
): Readonly<Ref<Readonly<T>>>
// 可写的
function computed<T>(
options: {
get: () => T
set: (value: T) => void
},
debuggerOptions?: DebuggerOptions
): Ref<T>
只读的computed
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
可读可写的computed
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
computed 源码解析
源码地址:/packages/reactivity/src/computed.ts
// 函数重载 支持多种参数传递方式
export function computed<T>(
getter: ComputedGetter<T>,
debugOptions?: DebuggerOptions
): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>,
debugOptions?: DebuggerOptions
): WritableComputedRef<T>
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions,
isSSR = false
) {
let getter: ComputedGetter<T>
let setter: ComputedSetter<T>
// 从上面我们知道computed可以接收函数或者对象作为参数
// 这里判断如果传递过来的是一个函数,那么就是只读的
const onlyGetter = isFunction(getterOrOptions)
if (onlyGetter) {
getter = getterOrOptions // 把传递过来的参数赋值给getter
setter = __DEV__ // 如果设置值,就直接警告
? () => {
console.warn('Write operation failed: computed value is readonly')
}
: NOOP
} else {
// 如果传递过来的是一个对象,就把对象的get/set分别赋值给getter/setter
getter = getterOrOptions.get
setter = getterOrOptions.set
}
// 将处理过的参数传递给了ComputedRefImpl类,源码在下面
const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)
if (__DEV__ && debugOptions && !isSSR) {
cRef.effect.onTrack = debugOptions.onTrack
cRef.effect.onTrigger = debugOptions.onTrigger
}
return cRef as any
}
ComputedRefImpl
export class ComputedRefImpl<T> {
public dep?: Dep = undefined
private _value!: T
public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true
public readonly [ReactiveFlags.IS_READONLY]: boolean = false
public _dirty = true // 脏值检测,如果为true就是重新计算,默认为true,相当于创建时就会计算
public _cacheable: boolean // 是否已缓存了计算的值
constructor(
getter: ComputedGetter<T>,
private readonly _setter: ComputedSetter<T>,
isReadonly: boolean,
isSSR: boolean
) {
// 依赖变化了 脏值为false才会走下面这里
// ReactiveEffect 只有依赖项发现改变才会执行
this.effect = new ReactiveEffect(getter, () => {
if (!this._dirty) { // 缓存的
this._dirty = true
triggerRefValue(this)
}
})
this.effect.computed = this
this.effect.active = this._cacheable = !isSSR
this[ReactiveFlags.IS_READONLY] = isReadonly
}
get value() {
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
const self = toRaw(this)
trackRefValue(self)
// 如果_dirty的值为true或者没有缓存就重新计算
if (self._dirty || !self._cacheable) {
self._dirty = false // 计算完就不是脏值了
self._value = self.effect.run()!
}
// 如果值没变就不再计算,直接返回
return self._value
}
set value(newValue: T) {
this._setter(newValue)
}
}