Skip to content

Commit 1867591

Browse files
committed
fix(reactivity): dereference nested effect scopes on manual stop
1 parent da6c055 commit 1867591

File tree

2 files changed

+16
-2
lines changed

2 files changed

+16
-2
lines changed

packages/reactivity/__tests__/effectScope.spec.ts

+8
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,14 @@ describe('reactivity/effect/scope', () => {
191191
expect(dummy).toBe(7)
192192
})
193193

194+
it('should derefence child scope from parent scope after stopping child scope (no memleaks)', async () => {
195+
const parent = new EffectScope()
196+
const child = parent.run(() => new EffectScope())!
197+
expect(parent.effects.includes(child)).toBe(true)
198+
child.stop()
199+
expect(parent.effects.includes(child)).toBe(false)
200+
})
201+
194202
it('test with higher level APIs', async () => {
195203
const r = ref(1)
196204

packages/reactivity/src/effectScope.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { remove } from '@vue/shared'
12
import { ReactiveEffect } from './effect'
23
import { warn } from './warning'
34

@@ -8,10 +9,12 @@ export class EffectScope {
89
active = true
910
effects: (ReactiveEffect | EffectScope)[] = []
1011
cleanups: (() => void)[] = []
12+
parent: EffectScope | undefined
1113

1214
constructor(detached = false) {
1315
if (!detached) {
1416
recordEffectScope(this)
17+
this.parent = activeEffectScope
1518
}
1619
}
1720

@@ -42,11 +45,14 @@ export class EffectScope {
4245
}
4346
}
4447

45-
stop() {
48+
stop(fromParent = false) {
4649
if (this.active) {
47-
this.effects.forEach(e => e.stop())
50+
this.effects.forEach(e => e.stop(true))
4851
this.cleanups.forEach(cleanup => cleanup())
4952
this.active = false
53+
if (!fromParent && this.parent) {
54+
remove(this.parent.effects, this)
55+
}
5056
}
5157
}
5258
}

0 commit comments

Comments
 (0)