From cf86e32575094e1d3d6344137b001b0b6dd5daa1 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 29 May 2019 18:44:50 +0800 Subject: [PATCH] wip: computed --- packages/observer/__tests__/value.spec.ts | 0 packages/observer/src/computed.ts | 40 +++++++++++++---------- packages/observer/src/index.ts | 4 +-- packages/observer/src/value.ts | 9 +++-- 4 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 packages/observer/__tests__/value.spec.ts diff --git a/packages/observer/__tests__/value.spec.ts b/packages/observer/__tests__/value.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/observer/src/computed.ts b/packages/observer/src/computed.ts index b74f8ca54..5a517f780 100644 --- a/packages/observer/src/computed.ts +++ b/packages/observer/src/computed.ts @@ -1,15 +1,16 @@ import { effect } from './index' import { ReactiveEffect, activeReactiveEffectStack } from './effect' +import { knownValues } from './value' -export interface ComputedGetter { - (): T - effect: ReactiveEffect +export interface ComputedValue { + readonly value: T + readonly effect: ReactiveEffect } export function computed( getter: (this: C, ctx: C) => T, context?: C -): ComputedGetter { +): ComputedValue { let dirty: boolean = true let value: any = undefined const runner = effect(() => getter.call(context, context), { @@ -18,22 +19,25 @@ export function computed( dirty = true } }) - const computedGetter = (() => { - if (dirty) { - value = runner() - dirty = false - } - // When computed effects are accessed in a parent effect, the parent - // should track all the dependencies the computed property has tracked. - // This should also apply for chained computed properties. - trackChildRun(runner) - return value - }) as ComputedGetter - // expose effect so computed can be stopped - computedGetter.effect = runner // mark effect as computed so that it gets priority during trigger runner.computed = true - return computedGetter + const computedValue = { + // expose effect so computed can be stopped + effect: runner, + get value() { + if (dirty) { + value = runner() + dirty = false + } + // When computed effects are accessed in a parent effect, the parent + // should track all the dependencies the computed property has tracked. + // This should also apply for chained computed properties. + trackChildRun(runner) + return value + } + } + knownValues.add(computedValue) + return computedValue } function trackChildRun(childRunner: ReactiveEffect) { diff --git a/packages/observer/src/index.ts b/packages/observer/src/index.ts index 35b13ec39..423126fc1 100644 --- a/packages/observer/src/index.ts +++ b/packages/observer/src/index.ts @@ -26,9 +26,9 @@ import { export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent } export { OperationTypes } from './operations' -export { computed, ComputedGetter } from './computed' +export { computed, ComputedValue } from './computed' export { lock, unlock } from './lock' -export { value, isValue } from './value' +export { value, isValue, Value } from './value' const collectionTypes: Set = new Set([Set, Map, WeakMap, WeakSet]) const observableValueRE = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/ diff --git a/packages/observer/src/value.ts b/packages/observer/src/value.ts index b37e100c2..534ee352a 100644 --- a/packages/observer/src/value.ts +++ b/packages/observer/src/value.ts @@ -1,20 +1,25 @@ import { track, trigger } from './effect' import { OperationTypes } from './operations' +import { isObject } from '@vue/shared' +import { observable } from './index' -const knownValues = new WeakSet() +export const knownValues = new WeakSet() export interface Value { value: T } +const convert = (val: any): any => (isObject(val) ? observable(val) : val) + export function value(raw: T): Value { + raw = convert(raw) const v = { get value() { track(v, OperationTypes.GET, '') return raw }, set value(newVal) { - raw = newVal + raw = convert(newVal) trigger(v, OperationTypes.SET, '') } }