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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user