Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e473e23

Browse files
authored
fix(teleport): should not mount deferred teleport after unmount (#14598)
1 parent e79b814 commit e473e23

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

‎packages/runtime-vapor/__tests__/components/Teleport.spec.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,35 @@ describe('renderer: VaporTeleport', () => {
130130
`<!--teleport start--><!--teleport end--><div>Footer</div><div id="targetId"><div>bar</div></div><!--if-->`,
131131
)
132132
})
133+
134+
test('should not mount deferred teleport content after unmount', async () => {
135+
const root = document.createElement('div')
136+
const target = document.createElement('div')
137+
const show = ref(true)
138+
const { mount } = define({
139+
setup() {
140+
return createIf(
141+
() => show.value,
142+
() =>
143+
createComp(
144+
VaporTeleport,
145+
{
146+
to: () => target,
147+
defer: () => true,
148+
},
149+
{ default: () => template('<div>teleported</div>')() },
150+
),
151+
() => template('<div>root</div>')(),
152+
)
153+
},
154+
}).create()
155+
mount(root)
156+
157+
show.value = false
158+
await nextTick()
159+
160+
expect(target.innerHTML).toBe('')
161+
})
133162
})
134163

135164
describe('HMR', () => {

‎packages/runtime-vapor/src/components/Teleport.ts‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
type GenericComponentInstance,
44
MismatchTypes,
55
MoveType,
6+
type SchedulerJob,
7+
SchedulerJobFlags,
68
type TeleportProps,
79
type TeleportTargetElement,
810
isMismatchAllowed,
@@ -82,6 +84,8 @@ export class TeleportFragment extends VaporFragment {
8284
mountContainer?: ParentNode | null
8385
mountAnchor?: Node | null
8486

87+
private mountToTargetJob?: SchedulerJob
88+
8589
constructor(props: LooseRawProps, slots?: LooseRawSlots | null) {
8690
super([])
8791
this.rawProps = props
@@ -273,7 +277,21 @@ export class TeleportFragment extends VaporFragment {
273277
// typically due to an early insertion caused by setInsertionState.
274278
!this.parent!.isConnected
275279
) {
276-
queuePostFlushCb(this.mountToTarget.bind(this))
280+
// Reuse one queued mount job per Teleport instance so repeated
281+
// updates in the same flush don't enqueue duplicate target mounts.
282+
// If the previous job was disposed during unmount, recreate it.
283+
if (
284+
!this.mountToTargetJob ||
285+
this.mountToTargetJob.flags! & SchedulerJobFlags.DISPOSED
286+
) {
287+
this.mountToTargetJob = () => {
288+
this.mountToTargetJob = undefined
289+
// State may have changed before the post-flush job runs.
290+
if (this.isDisabled || !this.anchor) return
291+
this.mountToTarget()
292+
}
293+
}
294+
queuePostFlushCb(this.mountToTargetJob)
277295
} else {
278296
this.mountToTarget()
279297
}
@@ -297,6 +315,11 @@ export class TeleportFragment extends VaporFragment {
297315
}
298316

299317
remove = (parent: ParentNode | undefined = this.parent!): void => {
318+
if (this.mountToTargetJob) {
319+
this.mountToTargetJob.flags! |= SchedulerJobFlags.DISPOSED
320+
this.mountToTargetJob = undefined
321+
}
322+
300323
// remove nodes
301324
if (this.nodes && this.mountContainer) {
302325
remove(this.nodes, this.mountContainer)

0 commit comments

Comments
 (0)