Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(reactivity): avoid error during nested watch stop #5806

Closed
wants to merge 11 commits into from
8 changes: 6 additions & 2 deletions packages/reactivity/src/effectScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ export class EffectScope {
stop(fromParent?: boolean): void {
if (this._active) {
let i, l
for (i = 0, l = this.effects.length; i < l; i++) {
this.effects[i].stop()
// #5783
// effects will be changed when a watch stopped.
// so we need to copy it for iteration.
const effectsToStop = this.effects.slice()
for (i = 0, l = effectsToStop.length; i < l; i++) {
effectsToStop[i].stop()
}
for (i = 0, l = this.cleanups.length; i < l; i++) {
this.cleanups[i]()
Expand Down
37 changes: 37 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,43 @@ describe('api: watch', () => {
expect(spy).toHaveBeenCalledTimes(2)
})

test('removing a watcher while stopping its effectScope', async () => {
const count = ref(0)
const scope = effectScope()
let watcherCalls = 0
let cleanupCalls = 0

scope.run(() => {
const stop1 = watch(count, () => {
watcherCalls++
})
watch(count, (val, old, onCleanup) => {
watcherCalls++
onCleanup(() => {
cleanupCalls++
stop1()
})
})
watch(count, () => {
watcherCalls++
})
})

expect(watcherCalls).toBe(0)
expect(cleanupCalls).toBe(0)

count.value++
await nextTick()
expect(watcherCalls).toBe(3)
expect(cleanupCalls).toBe(0)

scope.stop()
count.value++
await nextTick()
expect(watcherCalls).toBe(3)
expect(cleanupCalls).toBe(1)
})

it('watching sources: ref<any[]>', async () => {
const foo = ref([1])
const spy = vi.fn()
Expand Down