Просмотр исходного кода

fix(suspense): avoid updating anchor if activeBranch has not been rendered to the actual container (#11818)

close #11806
edison 1 год назад
Родитель
Сommit
3c0d531fa7

+ 1 - 1
packages/runtime-core/src/components/Suspense.ts

@@ -566,7 +566,7 @@ function createSuspenseBoundary(
           // (got `pendingBranch.el`).
           // Therefore, after the mounting of activeBranch is completed,
           // it is necessary to get the latest anchor.
-          if (parentNode(activeBranch.el!) !== suspense.hiddenContainer) {
+          if (parentNode(activeBranch.el!) === container) {
             anchor = next(activeBranch)
           }
           unmount(activeBranch, parentComponent, suspense, true)

+ 60 - 0
packages/vue/__tests__/e2e/Transition.spec.ts

@@ -2162,6 +2162,66 @@ describe('e2e: Transition', () => {
       },
       E2E_TIMEOUT,
     )
+
+    // #11806
+    test(
+      'switch between Async and Sync child when transition is not finished',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, shallowRef, h, nextTick } = (window as any).Vue
+          createApp({
+            template: `
+            <div id="container">
+              <Transition mode="out-in">
+                <Suspense>
+                  <component :is="view"/>
+                </Suspense>
+              </Transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const view = shallowRef('SyncB')
+              const click = async () => {
+                view.value = 'SyncA'
+                await nextTick()
+                view.value = 'AsyncB'
+                await nextTick()
+                view.value = 'SyncB'
+              }
+              return { view, click }
+            },
+            components: {
+              SyncA: {
+                setup() {
+                  return () => h('div', 'SyncA')
+                },
+              },
+              AsyncB: {
+                async setup() {
+                  await nextTick()
+                  return () => h('div', 'AsyncB')
+                },
+              },
+              SyncB: {
+                setup() {
+                  return () => h('div', 'SyncB')
+                },
+              },
+            },
+          }).mount('#app')
+        })
+
+        expect(await html('#container')).toBe('<div>SyncB</div>')
+
+        await click('#toggleBtn')
+        await nextFrame()
+        await transitionFinish()
+        await transitionFinish()
+        expect(await html('#container')).toBe('<div class="">SyncB</div>')
+      },
+      E2E_TIMEOUT,
+    )
   })
 
   describe('transition with Teleport', () => {