mirror of https://github.com/vuejs/core.git
fix(ssr): avoid updating subtree of async component if it is resolved (#12363)
close #12362
This commit is contained in:
parent
1f75d4e6df
commit
da7ad5e3d2
|
@ -1324,6 +1324,84 @@ describe('SSR hydration', () => {
|
||||||
resolve({})
|
resolve({})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//#12362
|
||||||
|
test('nested async wrapper', async () => {
|
||||||
|
const Toggle = defineAsyncComponent(
|
||||||
|
() =>
|
||||||
|
new Promise(r => {
|
||||||
|
r(
|
||||||
|
defineComponent({
|
||||||
|
setup(_, { slots }) {
|
||||||
|
const show = ref(false)
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
show.value = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
withDirectives(
|
||||||
|
h('div', null, [renderSlot(slots, 'default')]),
|
||||||
|
[[vShow, show.value]],
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}) as any,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const Wrapper = defineAsyncComponent(() => {
|
||||||
|
return new Promise(r => {
|
||||||
|
r(
|
||||||
|
defineComponent({
|
||||||
|
render(this: any) {
|
||||||
|
return renderSlot(this.$slots, 'default')
|
||||||
|
},
|
||||||
|
}) as any,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const count = ref(0)
|
||||||
|
const fn = vi.fn()
|
||||||
|
const Child = {
|
||||||
|
setup() {
|
||||||
|
onMounted(() => {
|
||||||
|
fn()
|
||||||
|
count.value++
|
||||||
|
})
|
||||||
|
return () => h('div', count.value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(Toggle, null, {
|
||||||
|
default: () =>
|
||||||
|
h(Wrapper, null, {
|
||||||
|
default: () =>
|
||||||
|
h(Wrapper, null, {
|
||||||
|
default: () => h(Child),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = document.createElement('div')
|
||||||
|
root.innerHTML = await renderToString(h(App))
|
||||||
|
expect(root.innerHTML).toMatchInlineSnapshot(
|
||||||
|
`"<div style="display:none;"><!--[--><!--[--><!--[--><div>0</div><!--]--><!--]--><!--]--></div>"`,
|
||||||
|
)
|
||||||
|
|
||||||
|
createSSRApp(App).mount(root)
|
||||||
|
await nextTick()
|
||||||
|
await nextTick()
|
||||||
|
expect(root.innerHTML).toMatchInlineSnapshot(
|
||||||
|
`"<div style=""><!--[--><!--[--><!--[--><div>1</div><!--]--><!--]--><!--]--></div>"`,
|
||||||
|
)
|
||||||
|
expect(fn).toBeCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
test('unmount async wrapper before load (fragment)', async () => {
|
test('unmount async wrapper before load (fragment)', async () => {
|
||||||
let resolve: any
|
let resolve: any
|
||||||
const AsyncComp = defineAsyncComponent(
|
const AsyncComp = defineAsyncComponent(
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
normalizeVNode,
|
normalizeVNode,
|
||||||
} from './vnode'
|
} from './vnode'
|
||||||
import { flushPostFlushCbs } from './scheduler'
|
import { flushPostFlushCbs } from './scheduler'
|
||||||
import type { ComponentInternalInstance } from './component'
|
import type { ComponentInternalInstance, ComponentOptions } from './component'
|
||||||
import { invokeDirectiveHook } from './directives'
|
import { invokeDirectiveHook } from './directives'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import {
|
import {
|
||||||
|
@ -308,7 +308,10 @@ export function createHydrationFunctions(
|
||||||
// if component is async, it may get moved / unmounted before its
|
// if component is async, it may get moved / unmounted before its
|
||||||
// inner component is loaded, so we need to give it a placeholder
|
// inner component is loaded, so we need to give it a placeholder
|
||||||
// vnode that matches its adopted DOM.
|
// vnode that matches its adopted DOM.
|
||||||
if (isAsyncWrapper(vnode)) {
|
if (
|
||||||
|
isAsyncWrapper(vnode) &&
|
||||||
|
!(vnode.type as ComponentOptions).__asyncResolved
|
||||||
|
) {
|
||||||
let subTree
|
let subTree
|
||||||
if (isFragmentStart) {
|
if (isFragmentStart) {
|
||||||
subTree = createVNode(Fragment)
|
subTree = createVNode(Fragment)
|
||||||
|
|
Loading…
Reference in New Issue