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, onErrorCaptured,
shallowRef shallowRef
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { createApp } from 'vue'
describe('Suspense', () => { describe('Suspense', () => {
const deps: Promise<any>[] = [] const deps: Promise<any>[] = []
@ -1068,4 +1069,28 @@ describe('Suspense', () => {
expect(serializeInner(root)).toBe(`<div>two</div>`) expect(serializeInner(root)).toBe(`<div>two</div>`)
expect(calls).toEqual([`one mounted`, `one unmounted`, `two mounted`]) 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, anchor,
parentComponent, parentComponent,
isSVG, isSVG,
optimized,
rendererInternals rendererInternals
) )
} }
@ -121,8 +120,7 @@ function mountSuspense(
null, null,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
// now check if we have encountered any async deps // now check if we have encountered any async deps
if (suspense.deps > 0) { if (suspense.deps > 0) {
@ -135,8 +133,7 @@ function mountSuspense(
anchor, anchor,
parentComponent, parentComponent,
null, // fallback tree will not have suspense context null, // fallback tree will not have suspense context
isSVG, isSVG
optimized
) )
setActiveBranch(suspense, vnode.ssFallback!) setActiveBranch(suspense, vnode.ssFallback!)
} else { } else {
@ -152,7 +149,6 @@ function patchSuspense(
anchor: RendererNode | null, anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean,
{ p: patch, um: unmount, o: { createElement } }: RendererInternals { p: patch, um: unmount, o: { createElement } }: RendererInternals
) { ) {
const suspense = (n2.suspense = n1.suspense)! const suspense = (n2.suspense = n1.suspense)!
@ -173,8 +169,7 @@ function patchSuspense(
null, null,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
if (suspense.deps <= 0) { if (suspense.deps <= 0) {
suspense.resolve() suspense.resolve()
@ -186,8 +181,7 @@ function patchSuspense(
anchor, anchor,
parentComponent, parentComponent,
null, // fallback tree will not have suspense context null, // fallback tree will not have suspense context
isSVG, isSVG
optimized
) )
setActiveBranch(suspense, newFallback) setActiveBranch(suspense, newFallback)
} }
@ -220,8 +214,7 @@ function patchSuspense(
null, null,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
if (suspense.deps <= 0) { if (suspense.deps <= 0) {
suspense.resolve() suspense.resolve()
@ -233,8 +226,7 @@ function patchSuspense(
anchor, anchor,
parentComponent, parentComponent,
null, // fallback tree will not have suspense context null, // fallback tree will not have suspense context
isSVG, isSVG
optimized
) )
setActiveBranch(suspense, newFallback) setActiveBranch(suspense, newFallback)
} }
@ -247,8 +239,7 @@ function patchSuspense(
anchor, anchor,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
// force resolve // force resolve
suspense.resolve(true) suspense.resolve(true)
@ -261,8 +252,7 @@ function patchSuspense(
null, null,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
if (suspense.deps <= 0) { if (suspense.deps <= 0) {
suspense.resolve() suspense.resolve()
@ -279,8 +269,7 @@ function patchSuspense(
anchor, anchor,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
setActiveBranch(suspense, newBranch) setActiveBranch(suspense, newBranch)
} else { } else {
@ -300,8 +289,7 @@ function patchSuspense(
null, null,
parentComponent, parentComponent,
suspense, suspense,
isSVG, isSVG
optimized
) )
if (suspense.deps <= 0) { if (suspense.deps <= 0) {
// incoming branch has no async deps, resolve now. // incoming branch has no async deps, resolve now.
@ -327,7 +315,6 @@ export interface SuspenseBoundary {
parent: SuspenseBoundary | null parent: SuspenseBoundary | null
parentComponent: ComponentInternalInstance | null parentComponent: ComponentInternalInstance | null
isSVG: boolean isSVG: boolean
optimized: boolean
container: RendererElement container: RendererElement
hiddenContainer: RendererElement hiddenContainer: RendererElement
anchor: RendererNode | null anchor: RendererNode | null
@ -392,7 +379,6 @@ function createSuspenseBoundary(
parent, parent,
parentComponent, parentComponent,
isSVG, isSVG,
optimized,
container, container,
hiddenContainer, hiddenContainer,
anchor, anchor,
@ -499,8 +485,7 @@ function createSuspenseBoundary(
activeBranch, activeBranch,
parentComponent, parentComponent,
container, container,
isSVG, isSVG
optimized
} = suspense } = suspense
// invoke @fallback event // invoke @fallback event
@ -522,8 +507,7 @@ function createSuspenseBoundary(
anchor, anchor,
parentComponent, parentComponent,
null, // fallback tree will not have suspense context null, // fallback tree will not have suspense context
isSVG, isSVG
optimized
) )
setActiveBranch(suspense, fallbackVNode) setActiveBranch(suspense, fallbackVNode)
} }