Skip to content

Commit d65675d

Browse files
authored
fix(runtime-vapor): dynamic component work with insertionState (#13142)
1 parent b96447d commit d65675d

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

packages/runtime-vapor/__tests__/apiCreateDynamicComponent.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { nextTick, resolveDynamicComponent } from '@vue/runtime-dom'
33
import {
44
createComponentWithFallback,
55
createDynamicComponent,
6+
defineVaporComponent,
67
renderEffect,
78
setHtml,
89
setInsertionState,
@@ -79,4 +80,34 @@ describe('api: createDynamicComponent', () => {
7980
mount()
8081
expect(html()).toBe('<div><button>hi</button></div>')
8182
})
83+
84+
test('switch dynamic component children', async () => {
85+
const CompA = defineVaporComponent({
86+
setup() {
87+
return template('<div>A</div>')()
88+
},
89+
})
90+
const CompB = defineVaporComponent({
91+
setup() {
92+
return template('<div>B</div>')()
93+
},
94+
})
95+
96+
const current = shallowRef(CompA)
97+
const { html } = define({
98+
setup() {
99+
const t1 = template('<div></div>')
100+
const n2 = t1() as any
101+
setInsertionState(n2)
102+
createDynamicComponent(() => current.value)
103+
return n2
104+
},
105+
}).render()
106+
107+
expect(html()).toBe('<div><div>A</div><!--dynamic-component--></div>')
108+
109+
current.value = CompB
110+
await nextTick()
111+
expect(html()).toBe('<div><div>B</div><!--dynamic-component--></div>')
112+
})
82113
})

packages/runtime-vapor/src/apiCreateDynamicComponent.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
11
import { resolveDynamicComponent } from '@vue/runtime-dom'
2-
import { DynamicFragment, type VaporFragment } from './block'
2+
import { DynamicFragment, type VaporFragment, insert } from './block'
33
import { createComponentWithFallback } from './component'
44
import { renderEffect } from './renderEffect'
55
import type { RawProps } from './componentProps'
66
import type { RawSlots } from './componentSlots'
7+
import {
8+
insertionAnchor,
9+
insertionParent,
10+
resetInsertionState,
11+
} from './insertionState'
12+
import { isHydrating, locateHydrationNode } from './dom/hydration'
713

814
export function createDynamicComponent(
915
getter: () => any,
1016
rawProps?: RawProps | null,
1117
rawSlots?: RawSlots | null,
1218
isSingleRoot?: boolean,
1319
): VaporFragment {
20+
const _insertionParent = insertionParent
21+
const _insertionAnchor = insertionAnchor
22+
if (isHydrating) {
23+
locateHydrationNode()
24+
} else {
25+
resetInsertionState()
26+
}
27+
1428
const frag = __DEV__
1529
? new DynamicFragment('dynamic-component')
1630
: new DynamicFragment()
31+
1732
renderEffect(() => {
1833
const value = getter()
1934
frag.update(
@@ -27,5 +42,10 @@ export function createDynamicComponent(
2742
value,
2843
)
2944
})
45+
46+
if (!isHydrating && _insertionParent) {
47+
insert(frag, _insertionParent, _insertionAnchor)
48+
}
49+
3050
return frag
3151
}

0 commit comments

Comments
 (0)