fix(watch): ensure watchers respect detached scope

fix #4158
This commit is contained in:
Evan You
2021-07-20 14:32:17 -04:00
parent 2bdee50a59
commit bc7f9767f5
3 changed files with 46 additions and 15 deletions

View File

@@ -25,7 +25,8 @@ import {
TriggerOpTypes,
triggerRef,
shallowRef,
Ref
Ref,
effectScope
} from '@vue/reactivity'
import { watchPostEffect } from '../src/apiWatch'
@@ -848,7 +849,7 @@ describe('api: watch', () => {
})
// https://github.com/vuejs/vue-next/issues/2381
test('$watch should always register its effects with itw own instance', async () => {
test('$watch should always register its effects with its own instance', async () => {
let instance: ComponentInternalInstance | null
let _show: Ref<boolean>
@@ -889,14 +890,14 @@ describe('api: watch', () => {
expect(instance!).toBeDefined()
expect(instance!.scope.effects).toBeInstanceOf(Array)
// includes the component's own render effect AND the watcher effect
expect(instance!.scope.effects!.length).toBe(2)
expect(instance!.scope.effects.length).toBe(2)
_show!.value = false
await nextTick()
await nextTick()
expect(instance!.scope.effects![0].active).toBe(false)
expect(instance!.scope.effects[0].active).toBe(false)
})
test('this.$watch should pass `this.proxy` to watch source as the first argument ', () => {
@@ -1024,4 +1025,26 @@ describe('api: watch', () => {
expect(plus.value).toBe(true)
expect(count).toBe(0)
})
// #4158
test('watch should not register in owner component if created inside detached scope', () => {
let instance: ComponentInternalInstance
const Comp = {
setup() {
instance = getCurrentInstance()!
effectScope(true).run(() => {
watch(
() => 1,
() => {}
)
})
return () => ''
}
}
const root = nodeOps.createElement('div')
createApp(Comp).mount(root)
// should not record watcher in detached scope and only the instance's
// own update effect
expect(instance!.scope.effects.length).toBe(1)
})
})