mirror of https://github.com/vuejs/core.git
fix(suspense): don't immediately resolve suspense on last dep unmount (#13456)
close #13453
This commit is contained in:
parent
0562548ab3
commit
a8713159ee
|
@ -17,6 +17,8 @@ import {
|
|||
onUnmounted,
|
||||
ref,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveDynamicComponent,
|
||||
serializeInner,
|
||||
shallowRef,
|
||||
|
@ -2161,6 +2163,80 @@ describe('Suspense', () => {
|
|||
await Promise.all(deps)
|
||||
})
|
||||
|
||||
// #13453
|
||||
test('add new async deps during patching', async () => {
|
||||
const getComponent = (type: string) => {
|
||||
if (type === 'A') {
|
||||
return defineAsyncComponent({
|
||||
setup() {
|
||||
return () => h('div', 'A')
|
||||
},
|
||||
})
|
||||
}
|
||||
return defineAsyncComponent({
|
||||
setup() {
|
||||
return () => h('div', 'B')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const types = ref(['A'])
|
||||
const add = async () => {
|
||||
types.value.push('B')
|
||||
}
|
||||
|
||||
const update = async () => {
|
||||
// mount Suspense B
|
||||
// [Suspense A] -> [Suspense A(pending), Suspense B(pending)]
|
||||
await add()
|
||||
// patch Suspense B (still pending)
|
||||
// [Suspense A(pending), Suspense B(pending)] -> [Suspense B(pending)]
|
||||
types.value.shift()
|
||||
}
|
||||
|
||||
const Comp = {
|
||||
render(this: any) {
|
||||
return h(Fragment, null, [
|
||||
renderList(types.value, type => {
|
||||
return h(
|
||||
Suspense,
|
||||
{ key: type },
|
||||
{
|
||||
default: () => [
|
||||
renderSlot(this.$slots, 'default', { type: type }),
|
||||
],
|
||||
},
|
||||
)
|
||||
}),
|
||||
])
|
||||
},
|
||||
}
|
||||
|
||||
const App = {
|
||||
setup() {
|
||||
return () =>
|
||||
h(Comp, null, {
|
||||
default: (params: any) => [h(getComponent(params.type))],
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
const root = nodeOps.createElement('div')
|
||||
render(h(App), root)
|
||||
expect(serializeInner(root)).toBe(`<!---->`)
|
||||
|
||||
await Promise.all(deps)
|
||||
expect(serializeInner(root)).toBe(`<div>A</div>`)
|
||||
|
||||
update()
|
||||
await nextTick()
|
||||
// wait for both A and B to resolve
|
||||
await Promise.all(deps)
|
||||
// wait for new B to resolve
|
||||
await Promise.all(deps)
|
||||
expect(serializeInner(root)).toBe(`<div>B</div>`)
|
||||
})
|
||||
|
||||
describe('warnings', () => {
|
||||
// base function to check if a combination of slots warns or not
|
||||
function baseCheckWarn(
|
||||
|
|
|
@ -2326,24 +2326,6 @@ function baseCreateRenderer(
|
|||
instance.isUnmounted = true
|
||||
}, parentSuspense)
|
||||
|
||||
// A component with async dep inside a pending suspense is unmounted before
|
||||
// its async dep resolves. This should remove the dep from the suspense, and
|
||||
// cause the suspense to resolve immediately if that was the last dep.
|
||||
if (
|
||||
__FEATURE_SUSPENSE__ &&
|
||||
parentSuspense &&
|
||||
parentSuspense.pendingBranch &&
|
||||
!parentSuspense.isUnmounted &&
|
||||
instance.asyncDep &&
|
||||
!instance.asyncResolved &&
|
||||
instance.suspenseId === parentSuspense.pendingId
|
||||
) {
|
||||
parentSuspense.deps--
|
||||
if (parentSuspense.deps === 0) {
|
||||
parentSuspense.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
||||
devtoolsComponentRemoved(instance)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue