]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(Suspense): properly get anchor when mount fallback vnode (#9770)
authoredison <daiwei521@126.com>
Fri, 8 Dec 2023 04:29:15 +0000 (12:29 +0800)
committerGitHub <noreply@github.com>
Fri, 8 Dec 2023 04:29:15 +0000 (12:29 +0800)
close #9769

packages/runtime-core/__tests__/components/Suspense.spec.ts
packages/runtime-core/src/components/Suspense.ts

index d822a992816fde42e3eb53912e51d32c4263f208..6fec755106a196bdfcf91f51d30716b970a95946 100644 (file)
@@ -1185,6 +1185,72 @@ describe('Suspense', () => {
     expect(calls).toEqual([`one mounted`, `one unmounted`, `two mounted`])
   })
 
+  test('mount the fallback content is in the correct position', async () => {
+    const makeComp = (name: string, delay = 0) =>
+      defineAsyncComponent(
+        {
+          setup() {
+            return () => h('div', [name])
+          }
+        },
+        delay
+      )
+
+    const One = makeComp('one')
+    const Two = makeComp('two', 20)
+
+    const view = shallowRef(One)
+
+    const Comp = {
+      setup() {
+        return () =>
+          h('div', [
+            h(
+              Suspense,
+              {
+                timeout: 10
+              },
+              {
+                default: h(view.value),
+                fallback: h('div', 'fallback')
+              }
+            ),
+            h('div', 'three')
+          ])
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(
+      `<div><div>fallback</div><div>three</div></div>`
+    )
+
+    await deps[0]
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<div><div>one</div><div>three</div></div>`
+    )
+
+    view.value = Two
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<div><div>one</div><div>three</div></div>`
+    )
+
+    await new Promise(r => setTimeout(r, 10))
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<div><div>fallback</div><div>three</div></div>`
+    )
+
+    await deps[1]
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<div><div>two</div><div>three</div></div>`
+    )
+  })
+
   // #2214
   // Since suspense renders its own root like a component, it should not patch
   // its content in optimized mode.
index 5e5521b09be535ea28d6bdaaf857766e2cc9d63c..426ca0cd32c684f41c33f32b772b4d58cf62f57e 100644 (file)
@@ -582,6 +582,7 @@ function createSuspenseBoundary(
       // invoke @fallback event
       triggerEvent(vnode, 'onFallback')
 
+      const anchor = next(activeBranch!)
       const mountFallback = () => {
         if (!suspense.isInFallback) {
           return
@@ -591,7 +592,7 @@ function createSuspenseBoundary(
           null,
           fallbackVNode,
           container,
-          next(activeBranch!),
+          anchor,
           parentComponent,
           null, // fallback tree will not have suspense context
           isSVG,