]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(teleport): handle deferred teleport update before mounted (#12168)
authoredison <daiwei521@126.com>
Thu, 14 Nov 2024 12:55:18 +0000 (20:55 +0800)
committerGitHub <noreply@github.com>
Thu, 14 Nov 2024 12:55:18 +0000 (20:55 +0800)
close #12161

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

index 5dc333ad69022568f7aae231452da6df724cc045..79125cd04dfdccf918e27643e36d53e930e6586d 100644 (file)
@@ -87,6 +87,49 @@ describe('renderer: teleport', () => {
           `</div>`,
       )
     })
+
+    test('update before mounted with defer', async () => {
+      const root = document.createElement('div')
+      document.body.appendChild(root)
+
+      const show = ref(false)
+      const foo = ref('foo')
+      const Header = {
+        props: { foo: String },
+        setup(props: any) {
+          return () => h('div', props.foo)
+        },
+      }
+      const Footer = {
+        setup() {
+          foo.value = 'bar'
+          return () => h('div', 'Footer')
+        },
+      }
+      createDOMApp({
+        render() {
+          return show.value
+            ? [
+                h(
+                  Teleport,
+                  { to: '#targetId', defer: true },
+                  h(Header, { foo: foo.value }),
+                ),
+                h(Footer),
+                h('div', { id: 'targetId' }),
+              ]
+            : [h('div')]
+        },
+      }).mount(root)
+
+      expect(root.innerHTML).toMatchInlineSnapshot(`"<div></div>"`)
+
+      show.value = true
+      await nextTick()
+      expect(root.innerHTML).toMatchInlineSnapshot(
+        `"<!--teleport start--><!--teleport end--><div>Footer</div><div id="targetId"><div>bar</div></div>"`,
+      )
+    })
   })
 
   function runSharedTests(deferMode: boolean) {
index 5def1b2d72198591740f29b1514a1472a904bcb9..fe6fa36c1ca4a5730589b10ba8bcf359238c1742 100644 (file)
@@ -164,11 +164,32 @@ export const TeleportImpl = {
       }
 
       if (isTeleportDeferred(n2.props)) {
-        queuePostRenderEffect(mountToTarget, parentSuspense)
+        queuePostRenderEffect(() => {
+          mountToTarget()
+          n2.el!.__isMounted = true
+        }, parentSuspense)
       } else {
         mountToTarget()
       }
     } else {
+      if (isTeleportDeferred(n2.props) && !n1.el!.__isMounted) {
+        queuePostRenderEffect(() => {
+          TeleportImpl.process(
+            n1,
+            n2,
+            container,
+            anchor,
+            parentComponent,
+            parentSuspense,
+            namespace,
+            slotScopeIds,
+            optimized,
+            internals,
+          )
+          delete n1.el!.__isMounted
+        }, parentSuspense)
+        return
+      }
       // update content
       n2.el = n1.el
       n2.targetStart = n1.targetStart