Skip to content

Commit 0764c33

Browse files
committed
fix(reactivity): scheduled effect should not execute if stopped
fix #910
1 parent 5c33776 commit 0764c33

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

packages/reactivity/__tests__/effect.spec.ts

+22
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,28 @@ describe('reactivity/effect', () => {
678678
expect(dummy).toBe(3)
679679
})
680680

681+
it('stop with scheduler', () => {
682+
let dummy
683+
const obj = reactive({ prop: 1 })
684+
const queue: (() => void)[] = []
685+
const runner = effect(
686+
() => {
687+
dummy = obj.prop
688+
},
689+
{
690+
scheduler: e => queue.push(e)
691+
}
692+
)
693+
obj.prop = 2
694+
expect(dummy).toBe(1)
695+
expect(queue.length).toBe(1)
696+
stop(runner)
697+
698+
// a scheduled effect should not execute anymore after stopped
699+
queue.forEach(e => e())
700+
expect(dummy).toBe(1)
701+
})
702+
681703
it('events: onStop', () => {
682704
const onStop = jest.fn()
683705
const runner = effect(() => {}, {

packages/reactivity/src/effect.ts

+18-22
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type KeyToDepMap = Map<any, Dep>
1010
const targetMap = new WeakMap<any, KeyToDepMap>()
1111

1212
export interface ReactiveEffect<T = any> {
13-
(): T
13+
(...args: any[]): T
1414
_isEffect: true
1515
active: boolean
1616
raw: () => T
@@ -75,11 +75,26 @@ export function stop(effect: ReactiveEffect) {
7575
}
7676

7777
function createReactiveEffect<T = any>(
78-
fn: () => T,
78+
fn: (...args: any[]) => T,
7979
options: ReactiveEffectOptions
8080
): ReactiveEffect<T> {
8181
const effect = function reactiveEffect(...args: unknown[]): unknown {
82-
return run(effect, fn, args)
82+
if (!effect.active) {
83+
return options.scheduler ? undefined : fn(...args)
84+
}
85+
if (!effectStack.includes(effect)) {
86+
cleanup(effect)
87+
try {
88+
enableTracking()
89+
effectStack.push(effect)
90+
activeEffect = effect
91+
return fn(...args)
92+
} finally {
93+
effectStack.pop()
94+
resetTracking()
95+
activeEffect = effectStack[effectStack.length - 1]
96+
}
97+
}
8398
} as ReactiveEffect
8499
effect._isEffect = true
85100
effect.active = true
@@ -89,25 +104,6 @@ function createReactiveEffect<T = any>(
89104
return effect
90105
}
91106

92-
function run(effect: ReactiveEffect, fn: Function, args: unknown[]): unknown {
93-
if (!effect.active) {
94-
return fn(...args)
95-
}
96-
if (!effectStack.includes(effect)) {
97-
cleanup(effect)
98-
try {
99-
enableTracking()
100-
effectStack.push(effect)
101-
activeEffect = effect
102-
return fn(...args)
103-
} finally {
104-
effectStack.pop()
105-
resetTracking()
106-
activeEffect = effectStack[effectStack.length - 1]
107-
}
108-
}
109-
}
110-
111107
function cleanup(effect: ReactiveEffect) {
112108
const { deps } = effect
113109
if (deps.length) {

0 commit comments

Comments
 (0)