使用:
const myAge = computed({
get(){},
set(){},
})
const myAge = computed(() =>{
return age.value + 10;
})
effect(()=>{
console.log(myAge.value);
})
特性:
- 此方法默认不会执行
- 当访问属性的时候执行
- 当依赖属性变了不会立即重新计算,而是等下次再去访问的时候才会重新计算
class ComputedRefImpl<T> {
private _value!: T // 操作 的 value
private _dirty = true // 脏
public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true;
public readonly [ReactiveFlags.IS_READONLY]: boolean
constructor(
getter: ComputedGetter<T>, // 就是我们在 computed 里面写的函数
private readonly _setter: ComputedSetter<T>,
isReadonly: boolean
) {
// 计算属性默认会生成一个effect
this.effect = effect(getter, {
lazy: true, // 默认初始化不执行,当取值的时候才会执行
scheduler: () => { // 这个 scheduler 的作用是当我设置了 computed 里面的某个值后希望他能重新执行,就需要把_dirty 设置为true
if (!this._dirty) {
this._dirty = true
// 属性变化了更新
trigger(toRaw(this), TriggerOpTypes.SET, 'value')
}
}
})
this[ReactiveFlags.IS_READONLY] = isReadonly
}
get value() { // 计算属性也要收集依赖
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
const self = toRaw(this)
if (self._dirty) {
self._value = this.effect() // effect 会执行 fn 并返回结果
self._dirty = false // 缓存
}
/**
* 如果在 effect 中使用了 计算属性 计算后的值的话就需要 依赖收集
* effect(()=>{
* console.log(myAge.value);
* })
* 当访问了 value 属性时就会收集
*/
track(self, TrackOpTypes.GET, 'value')
return self._value
}
set value(newValue: T) {
this._setter(newValue)
}
}
export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>
): WritableComputedRef<T>
/**
* 以下两种情况:
* const myAge = computed({
get(){},
set(){},
})
const myAge = computed(() =>{
return age.value + 10;
})
* 此方法默认不会执行
* 当访问属性的时候执行
* 当依赖属性变了不会立即重新计算,而是等下次再去访问的时候才会重新计算
*
* vue2 和 vue3 computer 原理是不一样的
* vue2 是让 computed 依赖的属性记住 那个渲染 watcher
*/
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>
) {
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
}
return new ComputedRefImpl(
getter,
setter,
isFunction(getterOrOptions) || !getterOrOptions.set
) as any
}