Skip to content

Commit

Permalink
feat(reactivity): support onTrack/onTrigger debug options for computed
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jul 16, 2021
1 parent b7ea7c1 commit 5cea9a1
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 10 deletions.
76 changes: 75 additions & 1 deletion packages/reactivity/__tests__/computed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import {
ref,
WritableComputedRef,
isReadonly,
setComputedScheduler
setComputedScheduler,
DebuggerEvent,
toRaw,
TrackOpTypes,
ITERATE_KEY,
TriggerOpTypes
} from '../src'

describe('reactivity/computed', () => {
Expand Down Expand Up @@ -200,6 +205,75 @@ describe('reactivity/computed', () => {
expect(x.value).toBe(1)
})

it('debug: onTrack', () => {
let events: DebuggerEvent[] = []
const onTrack = jest.fn((e: DebuggerEvent) => {
events.push(e)
})
const obj = reactive({ foo: 1, bar: 2 })
const c = computed(() => (obj.foo, 'bar' in obj, Object.keys(obj)), {
onTrack
})
expect(c.value).toEqual(['foo', 'bar'])
expect(onTrack).toHaveBeenCalledTimes(3)
expect(events).toEqual([
{
effect: c.effect,
target: toRaw(obj),
type: TrackOpTypes.GET,
key: 'foo'
},
{
effect: c.effect,
target: toRaw(obj),
type: TrackOpTypes.HAS,
key: 'bar'
},
{
effect: c.effect,
target: toRaw(obj),
type: TrackOpTypes.ITERATE,
key: ITERATE_KEY
}
])
})

it('debug: onTrigger', () => {
let events: DebuggerEvent[] = []
const onTrigger = jest.fn((e: DebuggerEvent) => {
events.push(e)
})
const obj = reactive({ foo: 1 })
const c = computed(() => obj.foo, { onTrigger })

// computed won't trigger compute until accessed
c.value

obj.foo++
expect(c.value).toBe(2)
expect(onTrigger).toHaveBeenCalledTimes(1)
expect(events[0]).toEqual({
effect: c.effect,
target: toRaw(obj),
type: TriggerOpTypes.SET,
key: 'foo',
oldValue: 1,
newValue: 2
})

// @ts-ignore
delete obj.foo
expect(c.value).toBeUndefined()
expect(onTrigger).toHaveBeenCalledTimes(2)
expect(events[1]).toEqual({
effect: c.effect,
target: toRaw(obj),
type: TriggerOpTypes.DELETE,
key: 'foo',
oldValue: 2
})
})

describe('with scheduler', () => {
// a simple scheduler similar to the main Vue scheduler
const tick = Promise.resolve()
Expand Down
24 changes: 18 additions & 6 deletions packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactiveEffect } from './effect'
import { DebuggerOptions, ReactiveEffect } from './effect'
import { Ref, trackRefValue, triggerRefValue } from './ref'
import { isFunction, NOOP } from '@vue/shared'
import { ReactiveFlags, toRaw } from './reactive'
Expand Down Expand Up @@ -101,12 +101,17 @@ class ComputedRefImpl<T> {
}
}

export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>
getter: ComputedGetter<T>,
debugOptions?: DebuggerOptions
): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>,
debugOptions?: DebuggerOptions
): WritableComputedRef<T>
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions
) {
let getter: ComputedGetter<T>
let setter: ComputedSetter<T>
Expand All @@ -123,9 +128,16 @@ export function computed<T>(
setter = getterOrOptions.set
}

return new ComputedRefImpl(
const cRef = new ComputedRefImpl(
getter,
setter,
isFunction(getterOrOptions) || !getterOrOptions.set
) as any
)

if (__DEV__ && debugOptions) {
cRef.effect.onTrack = debugOptions.onTrack
cRef.effect.onTrigger = debugOptions.onTrigger
}

return cRef as any
}
9 changes: 6 additions & 3 deletions packages/reactivity/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,17 @@ function cleanupEffect(effect: ReactiveEffect) {
}
}

export interface ReactiveEffectOptions {
export interface DebuggerOptions {
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}

export interface ReactiveEffectOptions extends DebuggerOptions {
lazy?: boolean
scheduler?: EffectScheduler
scope?: EffectScope
allowRecurse?: boolean
onStop?: () => void
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}

export interface ReactiveEffectRunner<T = any> {
Expand Down
1 change: 1 addition & 0 deletions packages/reactivity/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export {
ReactiveEffectRunner,
ReactiveEffectOptions,
EffectScheduler,
DebuggerOptions,
DebuggerEvent
} from './effect'
export {
Expand Down

0 comments on commit 5cea9a1

Please sign in to comment.