Browse Source

wip: computed

Evan You 7 years ago
parent
commit
cf86e32575

+ 0 - 0
packages/observer/__tests__/value.spec.ts


+ 22 - 18
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 = any> {
-  (): T
-  effect: ReactiveEffect
+export interface ComputedValue<T> {
+  readonly value: T
+  readonly effect: ReactiveEffect
 }
 
 export function computed<T, C = null>(
   getter: (this: C, ctx: C) => T,
   context?: C
-): ComputedGetter<T> {
+): ComputedValue<T> {
   let dirty: boolean = true
   let value: any = undefined
   const runner = effect(() => getter.call(context, context), {
@@ -18,22 +19,25 @@ export function computed<T, C = null>(
       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) {

+ 2 - 2
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<any> = new Set([Set, Map, WeakMap, WeakSet])
 const observableValueRE = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/

+ 7 - 2
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<T> {
   value: T
 }
 
+const convert = (val: any): any => (isObject(val) ? observable(val) : val)
+
 export function value<T>(raw: T): Value<T> {
+  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, '')
     }
   }