fix(suspense): fix suspense nested child updates in template mode

fix #2214
This commit is contained in:
Evan You 2020-10-20 12:28:02 -04:00
parent 128ec460ec
commit 0227b4a697
2 changed files with 37 additions and 28 deletions

View File

@ -14,6 +14,7 @@ import {
onErrorCaptured,
shallowRef
} from '@vue/runtime-test'
import { createApp } from 'vue'
describe('Suspense', () => {
const deps: Promise<any>[] = []
@ -1068,4 +1069,28 @@ describe('Suspense', () => {
expect(serializeInner(root)).toBe(`<div>two</div>`)
expect(calls).toEqual([`one mounted`, `one unmounted`, `two mounted`])
})
// #2214
// Since suspense renders its own root like a component, it should not patch
// its content in optimized mode.
test('should not miss nested element updates when used in templates', async () => {
const n = ref(1)
const Comp = {
setup() {
return { n }
},
template: `
<Suspense>
<div><span>{{ n }}</span></div>
</Suspense>
`
}
const root = document.createElement('div')
createApp(Comp).mount(root)
expect(root.innerHTML).toBe(`<div><span>1</span></div>`)
n.value++
await nextTick()
expect(root.innerHTML).toBe(`<div><span>2</span></div>`)
})
})

View File

@ -69,7 +69,6 @@ export const SuspenseImpl = {
anchor,
parentComponent,
isSVG,
optimized,
rendererInternals
)
}
@ -121,8 +120,7 @@ function mountSuspense(
null,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
// now check if we have encountered any async deps
if (suspense.deps > 0) {
@ -135,8 +133,7 @@ function mountSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
optimized
isSVG
)
setActiveBranch(suspense, vnode.ssFallback!)
} else {
@ -152,7 +149,6 @@ function patchSuspense(
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean,
{ p: patch, um: unmount, o: { createElement } }: RendererInternals
) {
const suspense = (n2.suspense = n1.suspense)!
@ -173,8 +169,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
if (suspense.deps <= 0) {
suspense.resolve()
@ -186,8 +181,7 @@ function patchSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
optimized
isSVG
)
setActiveBranch(suspense, newFallback)
}
@ -220,8 +214,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
if (suspense.deps <= 0) {
suspense.resolve()
@ -233,8 +226,7 @@ function patchSuspense(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
optimized
isSVG
)
setActiveBranch(suspense, newFallback)
}
@ -247,8 +239,7 @@ function patchSuspense(
anchor,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
// force resolve
suspense.resolve(true)
@ -261,8 +252,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
if (suspense.deps <= 0) {
suspense.resolve()
@ -279,8 +269,7 @@ function patchSuspense(
anchor,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
setActiveBranch(suspense, newBranch)
} else {
@ -300,8 +289,7 @@ function patchSuspense(
null,
parentComponent,
suspense,
isSVG,
optimized
isSVG
)
if (suspense.deps <= 0) {
// incoming branch has no async deps, resolve now.
@ -327,7 +315,6 @@ export interface SuspenseBoundary {
parent: SuspenseBoundary | null
parentComponent: ComponentInternalInstance | null
isSVG: boolean
optimized: boolean
container: RendererElement
hiddenContainer: RendererElement
anchor: RendererNode | null
@ -392,7 +379,6 @@ function createSuspenseBoundary(
parent,
parentComponent,
isSVG,
optimized,
container,
hiddenContainer,
anchor,
@ -499,8 +485,7 @@ function createSuspenseBoundary(
activeBranch,
parentComponent,
container,
isSVG,
optimized
isSVG
} = suspense
// invoke @fallback event
@ -522,8 +507,7 @@ function createSuspenseBoundary(
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
optimized
isSVG
)
setActiveBranch(suspense, fallbackVNode)
}