feat(reactivity): support onTrack/onTrigger debug options for computed
This commit is contained in:
parent
b7ea7c1485
commit
5cea9a1d4e
@ -5,7 +5,12 @@ import {
|
||||
ref,
|
||||
WritableComputedRef,
|
||||
isReadonly,
|
||||
setComputedScheduler
|
||||
setComputedScheduler,
|
||||
DebuggerEvent,
|
||||
toRaw,
|
||||
TrackOpTypes,
|
||||
ITERATE_KEY,
|
||||
TriggerOpTypes
|
||||
} from '../src'
|
||||
|
||||
describe('reactivity/computed', () => {
|
||||
@ -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()
|
||||
|
@ -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'
|
||||
@ -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>
|
||||
@ -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
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -50,6 +50,7 @@ export {
|
||||
ReactiveEffectRunner,
|
||||
ReactiveEffectOptions,
|
||||
EffectScheduler,
|
||||
DebuggerOptions,
|
||||
DebuggerEvent
|
||||
} from './effect'
|
||||
export {
|
||||
|
Loading…
Reference in New Issue
Block a user