fix(runtime-core): vnode hooks should not be called on async wrapper (#4349)
fix #4346
This commit is contained in:
parent
3201224ecb
commit
cd2d98499e
@ -744,4 +744,59 @@ describe('api: defineAsyncComponent', () => {
|
|||||||
expect(serializeInner(root)).toBe('<!---->')
|
expect(serializeInner(root)).toBe('<!---->')
|
||||||
expect(fooRef.value).toBe(null)
|
expect(fooRef.value).toBe(null)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('vnode hooks on async wrapper', async () => {
|
||||||
|
let resolve: (comp: Component) => void
|
||||||
|
const Foo = defineAsyncComponent(
|
||||||
|
() =>
|
||||||
|
new Promise(r => {
|
||||||
|
resolve = r as any
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const updater = ref(0)
|
||||||
|
|
||||||
|
const vnodeHooks = {
|
||||||
|
onVnodeBeforeMount: jest.fn(),
|
||||||
|
onVnodeMounted: jest.fn(),
|
||||||
|
onVnodeBeforeUpdate: jest.fn(),
|
||||||
|
onVnodeUpdated: jest.fn(),
|
||||||
|
onVnodeBeforeUnmount: jest.fn(),
|
||||||
|
onVnodeUnmounted: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggle = ref(true)
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
createApp({
|
||||||
|
render: () => (toggle.value ? [h(Foo, vnodeHooks), updater.value] : null)
|
||||||
|
}).mount(root)
|
||||||
|
|
||||||
|
expect(serializeInner(root)).toBe('<!---->0')
|
||||||
|
|
||||||
|
resolve!({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
id: 'foo'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: () => 'resolved'
|
||||||
|
})
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
expect(serializeInner(root)).toBe('resolved0')
|
||||||
|
expect(vnodeHooks.onVnodeBeforeMount).toHaveBeenCalledTimes(1)
|
||||||
|
expect(vnodeHooks.onVnodeMounted).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
updater.value++
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe('resolved1')
|
||||||
|
expect(vnodeHooks.onVnodeBeforeUpdate).toHaveBeenCalledTimes(1)
|
||||||
|
expect(vnodeHooks.onVnodeUpdated).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
toggle.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe('<!---->')
|
||||||
|
expect(vnodeHooks.onVnodeBeforeUnmount).toHaveBeenCalledTimes(1)
|
||||||
|
expect(vnodeHooks.onVnodeUnmounted).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1316,6 +1316,7 @@ function baseCreateRenderer(
|
|||||||
let vnodeHook: VNodeHook | null | undefined
|
let vnodeHook: VNodeHook | null | undefined
|
||||||
const { el, props } = initialVNode
|
const { el, props } = initialVNode
|
||||||
const { bm, m, parent } = instance
|
const { bm, m, parent } = instance
|
||||||
|
const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
|
||||||
|
|
||||||
effect.allowRecurse = false
|
effect.allowRecurse = false
|
||||||
// beforeMount hook
|
// beforeMount hook
|
||||||
@ -1323,7 +1324,10 @@ function baseCreateRenderer(
|
|||||||
invokeArrayFns(bm)
|
invokeArrayFns(bm)
|
||||||
}
|
}
|
||||||
// onVnodeBeforeMount
|
// onVnodeBeforeMount
|
||||||
if ((vnodeHook = props && props.onVnodeBeforeMount)) {
|
if (
|
||||||
|
!isAsyncWrapperVNode &&
|
||||||
|
(vnodeHook = props && props.onVnodeBeforeMount)
|
||||||
|
) {
|
||||||
invokeVNodeHook(vnodeHook, parent, initialVNode)
|
invokeVNodeHook(vnodeHook, parent, initialVNode)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@ -1359,7 +1363,7 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAsyncWrapper(initialVNode)) {
|
if (isAsyncWrapperVNode) {
|
||||||
;(initialVNode.type as ComponentOptions).__asyncLoader!().then(
|
;(initialVNode.type as ComponentOptions).__asyncLoader!().then(
|
||||||
// note: we are moving the render call into an async callback,
|
// note: we are moving the render call into an async callback,
|
||||||
// which means it won't track dependencies - but it's ok because
|
// which means it won't track dependencies - but it's ok because
|
||||||
@ -1400,7 +1404,10 @@ function baseCreateRenderer(
|
|||||||
queuePostRenderEffect(m, parentSuspense)
|
queuePostRenderEffect(m, parentSuspense)
|
||||||
}
|
}
|
||||||
// onVnodeMounted
|
// onVnodeMounted
|
||||||
if ((vnodeHook = props && props.onVnodeMounted)) {
|
if (
|
||||||
|
!isAsyncWrapperVNode &&
|
||||||
|
(vnodeHook = props && props.onVnodeMounted)
|
||||||
|
) {
|
||||||
const scopedInitialVNode = initialVNode
|
const scopedInitialVNode = initialVNode
|
||||||
queuePostRenderEffect(
|
queuePostRenderEffect(
|
||||||
() => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
|
() => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
|
||||||
@ -2085,9 +2092,13 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
|
const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs
|
||||||
|
const shouldInvokeVnodeHook = !isAsyncWrapper(vnode)
|
||||||
|
|
||||||
let vnodeHook: VNodeHook | undefined | null
|
let vnodeHook: VNodeHook | undefined | null
|
||||||
if ((vnodeHook = props && props.onVnodeBeforeUnmount)) {
|
if (
|
||||||
|
shouldInvokeVnodeHook &&
|
||||||
|
(vnodeHook = props && props.onVnodeBeforeUnmount)
|
||||||
|
) {
|
||||||
invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2140,7 +2151,11 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {
|
if (
|
||||||
|
(shouldInvokeVnodeHook &&
|
||||||
|
(vnodeHook = props && props.onVnodeUnmounted)) ||
|
||||||
|
shouldInvokeDirs
|
||||||
|
) {
|
||||||
queuePostRenderEffect(() => {
|
queuePostRenderEffect(() => {
|
||||||
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
|
||||||
shouldInvokeDirs &&
|
shouldInvokeDirs &&
|
||||||
|
Loading…
Reference in New Issue
Block a user