diff --git a/packages/runtime-core/__tests__/components/Teleport.spec.ts b/packages/runtime-core/__tests__/components/Teleport.spec.ts
index 4c35b1f2d..69a1c4cb2 100644
--- a/packages/runtime-core/__tests__/components/Teleport.spec.ts
+++ b/packages/runtime-core/__tests__/components/Teleport.spec.ts
@@ -16,6 +16,7 @@ import {
render,
serialize,
serializeInner,
+ useModel,
withDirectives,
} from '@vue/runtime-test'
import {
@@ -144,6 +145,62 @@ describe('renderer: teleport', () => {
`"
Footer
"`,
)
})
+
+ // #13349
+ test('handle deferred teleport updates before and after mount', async () => {
+ const root = document.createElement('div')
+ document.body.appendChild(root)
+
+ const show = ref(false)
+ const data2 = ref('2')
+ const data3 = ref('3')
+
+ const Comp = {
+ props: {
+ modelValue: {},
+ modelModifiers: {},
+ },
+ emits: ['update:modelValue'],
+ setup(props: any) {
+ const data2 = useModel(props, 'modelValue')
+ data2.value = '2+'
+ return () => h('span')
+ },
+ }
+
+ createDOMApp({
+ setup() {
+ setTimeout(() => (show.value = true), 5)
+ setTimeout(() => (data3.value = '3+'), 10)
+ },
+ render() {
+ return h(Fragment, null, [
+ h('span', { id: 'targetId001' }),
+ show.value
+ ? h(Fragment, null, [
+ h(Teleport, { to: '#targetId001', defer: true }, [
+ createTextVNode(String(data3.value)),
+ ]),
+ h(Comp, {
+ modelValue: data2.value,
+ 'onUpdate:modelValue': (event: any) =>
+ (data2.value = event),
+ }),
+ ])
+ : createCommentVNode('v-if'),
+ ])
+ },
+ }).mount(root)
+
+ expect(root.innerHTML).toMatchInlineSnapshot(
+ `""`,
+ )
+
+ await new Promise(r => setTimeout(r, 10))
+ expect(root.innerHTML).toMatchInlineSnapshot(
+ `"3+"`,
+ )
+ })
})
function runSharedTests(deferMode: boolean) {
diff --git a/packages/runtime-core/src/components/Teleport.ts b/packages/runtime-core/src/components/Teleport.ts
index fc2ee4c08..c37356a78 100644
--- a/packages/runtime-core/src/components/Teleport.ts
+++ b/packages/runtime-core/src/components/Teleport.ts
@@ -164,15 +164,16 @@ export const TeleportImpl = {
}
if (isTeleportDeferred(n2.props)) {
+ n2.el!.__isMounted = false
queuePostRenderEffect(() => {
mountToTarget()
- n2.el!.__isMounted = true
+ delete n2.el!.__isMounted
}, parentSuspense)
} else {
mountToTarget()
}
} else {
- if (isTeleportDeferred(n2.props) && !n1.el!.__isMounted) {
+ if (isTeleportDeferred(n2.props) && n1.el!.__isMounted === false) {
queuePostRenderEffect(() => {
TeleportImpl.process(
n1,
@@ -186,7 +187,6 @@ export const TeleportImpl = {
optimized,
internals,
)
- delete n1.el!.__isMounted
}, parentSuspense)
return
}