mirror of https://github.com/vuejs/core.git
fix(suspense/hydration): fix hydration timing of async component inside suspense
close #6638
This commit is contained in:
parent
e255c31c88
commit
1b8e197a5b
|
@ -688,6 +688,54 @@ describe('SSR hydration', () => {
|
||||||
expect(container.innerHTML).toBe(`<span>1</span>`)
|
expect(container.innerHTML).toBe(`<span>1</span>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #6638
|
||||||
|
test('Suspense + async component', async () => {
|
||||||
|
let isSuspenseResolved = false
|
||||||
|
let isSuspenseResolvedInChild: any
|
||||||
|
const AsyncChild = defineAsyncComponent(() =>
|
||||||
|
Promise.resolve(
|
||||||
|
defineComponent({
|
||||||
|
setup() {
|
||||||
|
isSuspenseResolvedInChild = isSuspenseResolved
|
||||||
|
const count = ref(0)
|
||||||
|
return () =>
|
||||||
|
h(
|
||||||
|
'span',
|
||||||
|
{
|
||||||
|
onClick: () => {
|
||||||
|
count.value++
|
||||||
|
},
|
||||||
|
},
|
||||||
|
count.value,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
const { vnode, container } = mountWithHydration('<span>0</span>', () =>
|
||||||
|
h(
|
||||||
|
Suspense,
|
||||||
|
{
|
||||||
|
onResolve() {
|
||||||
|
isSuspenseResolved = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
() => h(AsyncChild),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
expect(vnode.el).toBe(container.firstChild)
|
||||||
|
// wait for hydration to finish
|
||||||
|
await new Promise(r => setTimeout(r))
|
||||||
|
|
||||||
|
expect(isSuspenseResolvedInChild).toBe(false)
|
||||||
|
expect(isSuspenseResolved).toBe(true)
|
||||||
|
|
||||||
|
// assert interaction
|
||||||
|
triggerEvent('click', container.querySelector('span')!)
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(`<span>1</span>`)
|
||||||
|
})
|
||||||
|
|
||||||
test('Suspense (full integration)', async () => {
|
test('Suspense (full integration)', async () => {
|
||||||
const mountedCalls: number[] = []
|
const mountedCalls: number[] = []
|
||||||
const asyncDeps: Promise<any>[] = []
|
const asyncDeps: Promise<any>[] = []
|
||||||
|
|
|
@ -1276,7 +1276,7 @@ function baseCreateRenderer(
|
||||||
const componentUpdateFn = () => {
|
const componentUpdateFn = () => {
|
||||||
if (!instance.isMounted) {
|
if (!instance.isMounted) {
|
||||||
let vnodeHook: VNodeHook | null | undefined
|
let vnodeHook: VNodeHook | null | undefined
|
||||||
const { el, props } = initialVNode
|
const { el, props, type } = initialVNode
|
||||||
const { bm, m, parent } = instance
|
const { bm, m, parent } = instance
|
||||||
const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
|
const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
|
||||||
|
|
||||||
|
@ -1325,8 +1325,11 @@ function baseCreateRenderer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAsyncWrapperVNode) {
|
if (
|
||||||
;(initialVNode.type as ComponentOptions).__asyncLoader!().then(
|
isAsyncWrapperVNode &&
|
||||||
|
!(type as ComponentOptions).__asyncResolved
|
||||||
|
) {
|
||||||
|
;(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
|
||||||
// a server-rendered async wrapper is already in resolved state
|
// a server-rendered async wrapper is already in resolved state
|
||||||
|
|
Loading…
Reference in New Issue