parent
2bdee50a59
commit
bc7f9767f5
@ -25,7 +25,8 @@ import {
|
|||||||
TriggerOpTypes,
|
TriggerOpTypes,
|
||||||
triggerRef,
|
triggerRef,
|
||||||
shallowRef,
|
shallowRef,
|
||||||
Ref
|
Ref,
|
||||||
|
effectScope
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import { watchPostEffect } from '../src/apiWatch'
|
import { watchPostEffect } from '../src/apiWatch'
|
||||||
|
|
||||||
@ -848,7 +849,7 @@ describe('api: watch', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// https://github.com/vuejs/vue-next/issues/2381
|
// 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 instance: ComponentInternalInstance | null
|
||||||
let _show: Ref<boolean>
|
let _show: Ref<boolean>
|
||||||
|
|
||||||
@ -889,14 +890,14 @@ describe('api: watch', () => {
|
|||||||
expect(instance!).toBeDefined()
|
expect(instance!).toBeDefined()
|
||||||
expect(instance!.scope.effects).toBeInstanceOf(Array)
|
expect(instance!.scope.effects).toBeInstanceOf(Array)
|
||||||
// includes the component's own render effect AND the watcher effect
|
// 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
|
_show!.value = false
|
||||||
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
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 ', () => {
|
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(plus.value).toBe(true)
|
||||||
expect(count).toBe(0)
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
isInSSRComponentSetup
|
isInSSRComponentSetup,
|
||||||
|
setCurrentInstance,
|
||||||
|
unsetCurrentInstance
|
||||||
} from './component'
|
} from './component'
|
||||||
import {
|
import {
|
||||||
ErrorCodes,
|
ErrorCodes,
|
||||||
@ -157,8 +159,7 @@ export function watch<T = any, Immediate extends Readonly<boolean> = false>(
|
|||||||
function doWatch(
|
function doWatch(
|
||||||
source: WatchSource | WatchSource[] | WatchEffect | object,
|
source: WatchSource | WatchSource[] | WatchEffect | object,
|
||||||
cb: WatchCallback | null,
|
cb: WatchCallback | null,
|
||||||
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ,
|
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
|
||||||
instance = currentInstance
|
|
||||||
): WatchStopHandle {
|
): WatchStopHandle {
|
||||||
if (__DEV__ && !cb) {
|
if (__DEV__ && !cb) {
|
||||||
if (immediate !== undefined) {
|
if (immediate !== undefined) {
|
||||||
@ -184,6 +185,7 @@ function doWatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const instance = currentInstance
|
||||||
let getter: () => any
|
let getter: () => any
|
||||||
let forceTrigger = false
|
let forceTrigger = false
|
||||||
let isMultiSource = false
|
let isMultiSource = false
|
||||||
@ -340,8 +342,7 @@ function doWatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scope = instance && instance.scope
|
const effect = new ReactiveEffect(getter, scheduler)
|
||||||
const effect = new ReactiveEffect(getter, scheduler, scope)
|
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
effect.onTrack = onTrack
|
effect.onTrack = onTrack
|
||||||
@ -366,8 +367,8 @@ function doWatch(
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
effect.stop()
|
effect.stop()
|
||||||
if (scope) {
|
if (instance && instance.scope) {
|
||||||
remove(scope.effects!, effect)
|
remove(instance.scope.effects!, effect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,7 +393,15 @@ export function instanceWatch(
|
|||||||
cb = value.handler as Function
|
cb = value.handler as Function
|
||||||
options = value
|
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) {
|
export function createPathGetter(ctx: any, path: string) {
|
||||||
|
@ -2304,9 +2304,8 @@ function baseCreateRenderer(
|
|||||||
instance.emit('hook:beforeDestroy')
|
instance.emit('hook:beforeDestroy')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope) {
|
// stop effects in component scope
|
||||||
scope.stop()
|
scope.stop()
|
||||||
}
|
|
||||||
|
|
||||||
// update may be null if a component is unmounted before its async
|
// update may be null if a component is unmounted before its async
|
||||||
// setup has resolved.
|
// setup has resolved.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user