Skip to content

Commit 22dcbf3

Browse files
committed
fix(reactivity): ensure multiple effectScope on() and off() calls maintains correct active scope
close #12631 close #12632 This is a combination of changes from both 8dec243 and #12641
1 parent e8e8422 commit 22dcbf3

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

packages/reactivity/src/effectScope.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export class EffectScope {
88
* @internal
99
*/
1010
private _active = true
11+
/**
12+
* @internal track `on` calls, allow `on` call multiple times
13+
*/
14+
private _on = 0
1115
/**
1216
* @internal
1317
*/
@@ -99,20 +103,27 @@ export class EffectScope {
99103
}
100104
}
101105

106+
prevScope: EffectScope | undefined
102107
/**
103108
* This should only be called on non-detached scopes
104109
* @internal
105110
*/
106111
on(): void {
107-
activeEffectScope = this
112+
if (++this._on === 1) {
113+
this.prevScope = activeEffectScope
114+
activeEffectScope = this
115+
}
108116
}
109117

110118
/**
111119
* This should only be called on non-detached scopes
112120
* @internal
113121
*/
114122
off(): void {
115-
activeEffectScope = this.parent
123+
if (this._on > 0 && --this._on === 0) {
124+
activeEffectScope = this.prevScope
125+
this.prevScope = undefined
126+
}
116127
}
117128

118129
stop(fromParent?: boolean): void {

packages/runtime-core/__tests__/apiWatch.spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
TrackOpTypes,
3232
TriggerOpTypes,
3333
effectScope,
34+
onScopeDispose,
3435
shallowReactive,
3536
shallowRef,
3637
toRef,
@@ -1982,4 +1983,31 @@ describe('api: watch', () => {
19821983
expect(spy1).toHaveBeenCalled()
19831984
expect(spy2).toHaveBeenCalled()
19841985
})
1986+
1987+
// #12631
1988+
test('this.$watch w/ onScopeDispose', () => {
1989+
const onCleanup = vi.fn()
1990+
const toggle = ref(true)
1991+
1992+
const Comp = defineComponent({
1993+
render() {},
1994+
created(this: any) {
1995+
this.$watch(
1996+
() => 1,
1997+
function () {},
1998+
)
1999+
onScopeDispose(onCleanup)
2000+
},
2001+
})
2002+
2003+
const App = defineComponent({
2004+
render() {
2005+
return toggle.value ? h(Comp) : null
2006+
},
2007+
})
2008+
2009+
const root = nodeOps.createElement('div')
2010+
createApp(App).mount(root)
2011+
expect(onCleanup).toBeCalledTimes(0)
2012+
})
19852013
})

0 commit comments

Comments
 (0)