diff --git a/packages/reactivity/__tests__/effect.spec.ts b/packages/reactivity/__tests__/effect.spec.ts index 3ce0748b539..24ade5b7ca8 100644 --- a/packages/reactivity/__tests__/effect.spec.ts +++ b/packages/reactivity/__tests__/effect.spec.ts @@ -678,6 +678,28 @@ describe('reactivity/effect', () => { expect(dummy).toBe(3) }) + it('stop with scheduler', () => { + let dummy + const obj = reactive({ prop: 1 }) + const queue: (() => void)[] = [] + const runner = effect( + () => { + dummy = obj.prop + }, + { + scheduler: e => queue.push(e) + } + ) + obj.prop = 2 + expect(dummy).toBe(1) + expect(queue.length).toBe(1) + stop(runner) + + // a scheduled effect should not execute anymore after stopped + queue.forEach(e => e()) + expect(dummy).toBe(1) + }) + it('events: onStop', () => { const onStop = jest.fn() const runner = effect(() => {}, { diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index cc6d0a61d90..6a09640e88f 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -10,7 +10,7 @@ type KeyToDepMap = Map const targetMap = new WeakMap() export interface ReactiveEffect { - (): T + (...args: any[]): T _isEffect: true active: boolean raw: () => T @@ -75,11 +75,26 @@ export function stop(effect: ReactiveEffect) { } function createReactiveEffect( - fn: () => T, + fn: (...args: any[]) => T, options: ReactiveEffectOptions ): ReactiveEffect { const effect = function reactiveEffect(...args: unknown[]): unknown { - return run(effect, fn, args) + if (!effect.active) { + return options.scheduler ? undefined : fn(...args) + } + if (!effectStack.includes(effect)) { + cleanup(effect) + try { + enableTracking() + effectStack.push(effect) + activeEffect = effect + return fn(...args) + } finally { + effectStack.pop() + resetTracking() + activeEffect = effectStack[effectStack.length - 1] + } + } } as ReactiveEffect effect._isEffect = true effect.active = true @@ -89,25 +104,6 @@ function createReactiveEffect( return effect } -function run(effect: ReactiveEffect, fn: Function, args: unknown[]): unknown { - if (!effect.active) { - return fn(...args) - } - if (!effectStack.includes(effect)) { - cleanup(effect) - try { - enableTracking() - effectStack.push(effect) - activeEffect = effect - return fn(...args) - } finally { - effectStack.pop() - resetTracking() - activeEffect = effectStack[effectStack.length - 1] - } - } -} - function cleanup(effect: ReactiveEffect) { const { deps } = effect if (deps.length) {