diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts new file mode 100644 index 0000000..ef79bb1 --- /dev/null +++ b/packages/reactivity/src/computed.ts @@ -0,0 +1,30 @@ +import { isFunction } from '@vue/shared' +import { Dep } from './dep' +import { ReactiveEffect } from './effect' +import { trackRefValue } from './ref' + +export class ComputedRefImpl { + public dep?: Dep = undefined + private _value!: T + public readonly effect: ReactiveEffect + public readonly __v_isRef = true + constructor(getter) { + this.effect = new ReactiveEffect(getter) + this.effect.computed = this + } + get value() { + trackRefValue(this) //触发依赖 + this._value = this.effect.run() + return this._value + } +} + +export function computed(getterOrOptions) { + let getter + const onlyGetter = isFunction(getterOrOptions) + if (onlyGetter) { + getter = getterOrOptions + } + const cRef = new ComputedRefImpl(getter) + return cRef +} diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 7c40214..510db96 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -1,5 +1,6 @@ import { createDep, Dep } from './dep' import { isArray } from '@vue/shared' +import { ComputedRefImpl } from './computed' type KeyToDepMap = Map /** @@ -19,6 +20,7 @@ export function effect(fn: () => T) { export let activeEffect: ReactiveEffect | undefined export class ReactiveEffect { + computed?: ComputedRefImpl constructor(public fn: () => T) {} run() { //当前被激活的effect实例 diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 7a869fe..7964e45 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -1,3 +1,4 @@ export { reactive } from './reactive' export { effect } from './effect' export { ref } from './ref' +export { computed } from './computed' diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 480fe58..97d9207 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -9,3 +9,7 @@ export const isObject = (val: unknown) => */ export const hasChanged = (value: any, oldValue: any): boolean => !Object.is(value, oldValue) + +export const isFunction = (val: unknown): val is Function => { + return typeof val === 'function' +} diff --git a/packages/vue/examples/reactivity/computed.html b/packages/vue/examples/reactivity/computed.html new file mode 100644 index 0000000..a53b3e8 --- /dev/null +++ b/packages/vue/examples/reactivity/computed.html @@ -0,0 +1,26 @@ + + + + + Document + + + +
+ + + \ No newline at end of file diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 015eeb1..6a2f477 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -1 +1 @@ -export { reactive, effect, ref } from '@vue/reactivity' +export { reactive, effect, ref, computed } from '@vue/reactivity'