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 { effect } from './index'
import { ReactiveEffect, activeReactiveEffectStack } from './effect' import { ReactiveEffect, activeReactiveEffectStack } from './effect'
import { knownValues } from './value'
export interface ComputedGetter<T = any> { export interface ComputedValue<T> {
(): T readonly value: T
effect: ReactiveEffect readonly effect: ReactiveEffect
} }
export function computed<T, C = null>( export function computed<T, C = null>(
getter: (this: C, ctx: C) => T, getter: (this: C, ctx: C) => T,
context?: C context?: C
): ComputedGetter<T> { ): ComputedValue<T> {
let dirty: boolean = true let dirty: boolean = true
let value: any = undefined let value: any = undefined
const runner = effect(() => getter.call(context, context), { const runner = effect(() => getter.call(context, context), {
@ -18,7 +19,12 @@ export function computed<T, C = null>(
dirty = true dirty = true
} }
}) })
const computedGetter = (() => { // mark effect as computed so that it gets priority during trigger
runner.computed = true
const computedValue = {
// expose effect so computed can be stopped
effect: runner,
get value() {
if (dirty) { if (dirty) {
value = runner() value = runner()
dirty = false dirty = false
@ -28,12 +34,10 @@ export function computed<T, C = null>(
// This should also apply for chained computed properties. // This should also apply for chained computed properties.
trackChildRun(runner) trackChildRun(runner)
return value return value
}) as ComputedGetter }
// expose effect so computed can be stopped }
computedGetter.effect = runner knownValues.add(computedValue)
// mark effect as computed so that it gets priority during trigger return computedValue
runner.computed = true
return computedGetter
} }
function trackChildRun(childRunner: ReactiveEffect) { function trackChildRun(childRunner: ReactiveEffect) {

View File

@ -26,9 +26,9 @@ import {
export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent } export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent }
export { OperationTypes } from './operations' export { OperationTypes } from './operations'
export { computed, ComputedGetter } from './computed' export { computed, ComputedValue } from './computed'
export { lock, unlock } from './lock' 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 collectionTypes: Set<any> = new Set([Set, Map, WeakMap, WeakSet])
const observableValueRE = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/ const observableValueRE = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/

View File

@ -1,20 +1,25 @@
import { track, trigger } from './effect' import { track, trigger } from './effect'
import { OperationTypes } from './operations' 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> { export interface Value<T> {
value: T value: T
} }
const convert = (val: any): any => (isObject(val) ? observable(val) : val)
export function value<T>(raw: T): Value<T> { export function value<T>(raw: T): Value<T> {
raw = convert(raw)
const v = { const v = {
get value() { get value() {
track(v, OperationTypes.GET, '') track(v, OperationTypes.GET, '')
return raw return raw
}, },
set value(newVal) { set value(newVal) {
raw = newVal raw = convert(newVal)
trigger(v, OperationTypes.SET, '') trigger(v, OperationTypes.SET, '')
} }
} }