fix(suspense): fix suspense nested child updates in template mode
fix #2214
This commit is contained in:
		
							parent
							
								
									128ec460ec
								
							
						
					
					
						commit
						0227b4a697
					
				@ -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>`)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user