wip: computed

This commit is contained in:
Evan You 2019-05-29 18:44:50 +08:00
parent 02421dbe62
commit cf86e32575
4 changed files with 31 additions and 22 deletions

View File

@ -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) {

View File

@ -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)\]$/

View File

@ -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, '')
}
}