mirror of https://github.com/vuejs/core.git
fix(suspense): handle suspense switching with nested suspense (#10184)
close #10098
This commit is contained in:
parent
411596c07b
commit
0f3da05ea2
|
@ -22,7 +22,7 @@ import {
|
||||||
watch,
|
watch,
|
||||||
watchEffect,
|
watchEffect,
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { createApp, defineComponent } from 'vue'
|
import { computed, createApp, defineComponent, inject, provide } from 'vue'
|
||||||
import type { RawSlots } from 'packages/runtime-core/src/componentSlots'
|
import type { RawSlots } from 'packages/runtime-core/src/componentSlots'
|
||||||
import { resetSuspenseId } from '../../src/components/Suspense'
|
import { resetSuspenseId } from '../../src/components/Suspense'
|
||||||
|
|
||||||
|
@ -1039,6 +1039,99 @@ describe('Suspense', () => {
|
||||||
expect(serializeInner(root)).toBe(`<div>foo<div>foo nested</div></div>`)
|
expect(serializeInner(root)).toBe(`<div>foo<div>foo nested</div></div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10098
|
||||||
|
test('switching branches w/ nested suspense', async () => {
|
||||||
|
const RouterView = {
|
||||||
|
setup(_: any, { slots }: any) {
|
||||||
|
const route = inject('route') as any
|
||||||
|
const depth = inject('depth', 0)
|
||||||
|
provide('depth', depth + 1)
|
||||||
|
return () => {
|
||||||
|
const current = route.value[depth]
|
||||||
|
return slots.default({ Component: current })[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const OuterB = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: () => h(Component),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const InnerB = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerB')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const OuterA = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: () => h(Component),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const InnerA = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerA')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const toggle = ref(true)
|
||||||
|
const route = computed(() => {
|
||||||
|
return toggle.value ? [OuterA, InnerA] : [OuterB, InnerB]
|
||||||
|
})
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
provide('route', route)
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: () => h(Component),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Comp), root)
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<!---->`)
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>innerA</div>`)
|
||||||
|
|
||||||
|
deps.length = 0
|
||||||
|
|
||||||
|
toggle.value = false
|
||||||
|
await nextTick()
|
||||||
|
// toggle again
|
||||||
|
toggle.value = true
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>innerA</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
test('branch switch to 3rd branch before resolve', async () => {
|
test('branch switch to 3rd branch before resolve', async () => {
|
||||||
const calls: string[] = []
|
const calls: string[] = []
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,9 @@ export const SuspenseImpl = {
|
||||||
// it is necessary to skip the current patch to avoid multiple mounts
|
// it is necessary to skip the current patch to avoid multiple mounts
|
||||||
// of inner components.
|
// of inner components.
|
||||||
if (parentSuspense && parentSuspense.deps > 0) {
|
if (parentSuspense && parentSuspense.deps > 0) {
|
||||||
n2.suspense = n1.suspense
|
n2.suspense = n1.suspense!
|
||||||
|
n2.suspense.vnode = n2
|
||||||
|
n2.el = n1.el
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
patchSuspense(
|
patchSuspense(
|
||||||
|
|
Loading…
Reference in New Issue