Skip to content

Commit

Permalink
fix(watch): cleanup watcher effect from scope when manually stopped (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
yangmingshan committed Jan 4, 2024
1 parent f70f7ca commit d2d8955
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
31 changes: 31 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
6 changes: 4 additions & 2 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ReactiveEffect,
ReactiveFlags,
type Ref,
getCurrentScope,
isReactive,
isRef,
isShallow,
Expand Down Expand Up @@ -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)
}
}

Expand Down

0 comments on commit d2d8955

Please sign in to comment.