fix(watch): cleanup watcher effect from scope when manually stopped (#9978)

This commit is contained in:
Yang Mingshan 2024-01-04 10:36:13 +08:00 committed by GitHub
parent f70f7ca9ae
commit d2d89551bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 2 deletions

View File

@ -1443,4 +1443,35 @@ describe('api: watch', () => {
expect(spy1).toHaveBeenCalledTimes(1)
expect(spy2).toHaveBeenCalledTimes(1)
})
test("effect should be removed from scope's effects after it is stopped", () => {
const num = ref(0)
let unwatch: () => void
let instance: ComponentInternalInstance
const Comp = {
setup() {
instance = getCurrentInstance()!
unwatch = watch(num, () => {
console.log(num.value)
})
return () => null
},
}
const root = nodeOps.createElement('div')
createApp(Comp).mount(root)
expect(instance!.scope.effects.length).toBe(2)
unwatch!()
expect(instance!.scope.effects.length).toBe(1)
const scope = effectScope()
scope.run(() => {
unwatch = watch(num, () => {
console.log(num.value)
})
})
expect(scope.effects.length).toBe(1)
unwatch!()
expect(scope.effects.length).toBe(0)
})
})

View File

@ -5,6 +5,7 @@ import {
ReactiveEffect,
ReactiveFlags,
type Ref,
getCurrentScope,
isReactive,
isRef,
isShallow,
@ -394,10 +395,11 @@ function doWatch(
const effect = new ReactiveEffect(getter, NOOP, scheduler)
const scope = getCurrentScope()
const unwatch = () => {
effect.stop()
if (instance && instance.scope) {
remove(instance.scope.effects!, effect)
if (scope) {
remove(scope.effects, effect)
}
}