TriggerOpTypes,
triggerRef,
shallowRef,
- Ref
+ Ref,
+ effectScope
} from '@vue/reactivity'
import { watchPostEffect } from '../src/apiWatch'
})
// 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>
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 ', () => {
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)
+ })
})
import {
currentInstance,
ComponentInternalInstance,
- isInSSRComponentSetup
+ isInSSRComponentSetup,
+ setCurrentInstance,
+ unsetCurrentInstance
} from './component'
import {
ErrorCodes,
function doWatch(
source: WatchSource | WatchSource[] | WatchEffect | object,
cb: WatchCallback | null,
- { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ,
- instance = currentInstance
+ { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle {
if (__DEV__ && !cb) {
if (immediate !== undefined) {
)
}
+ const instance = currentInstance
let getter: () => any
let forceTrigger = false
let isMultiSource = false
}
}
- const scope = instance && instance.scope
- const effect = new ReactiveEffect(getter, scheduler, scope)
+ const effect = new ReactiveEffect(getter, scheduler)
if (__DEV__) {
effect.onTrack = onTrack
return () => {
effect.stop()
- if (scope) {
- remove(scope.effects!, effect)
+ if (instance && instance.scope) {
+ remove(instance.scope.effects!, effect)
}
}
}
cb = value.handler as Function
options = value
}
- return doWatch(getter, cb.bind(publicThis), options, this)
+ const cur = currentInstance
+ setCurrentInstance(this)
+ const res = doWatch(getter, cb.bind(publicThis), options)
+ if (cur) {
+ setCurrentInstance(cur)
+ } else {
+ unsetCurrentInstance()
+ }
+ return res
}
export function createPathGetter(ctx: any, path: string) {