import {
createComponentWithFallback,
createDynamicComponent,
+ defineVaporComponent,
renderEffect,
setHtml,
setInsertionState,
mount()
expect(html()).toBe('<div><button>hi</button></div>')
})
+
+ test('switch dynamic component children', async () => {
+ const CompA = defineVaporComponent({
+ setup() {
+ return template('<div>A</div>')()
+ },
+ })
+ const CompB = defineVaporComponent({
+ setup() {
+ return template('<div>B</div>')()
+ },
+ })
+
+ const current = shallowRef(CompA)
+ const { html } = define({
+ setup() {
+ const t1 = template('<div></div>')
+ const n2 = t1() as any
+ setInsertionState(n2)
+ createDynamicComponent(() => current.value)
+ return n2
+ },
+ }).render()
+
+ expect(html()).toBe('<div><div>A</div><!--dynamic-component--></div>')
+
+ current.value = CompB
+ await nextTick()
+ expect(html()).toBe('<div><div>B</div><!--dynamic-component--></div>')
+ })
})
import { resolveDynamicComponent } from '@vue/runtime-dom'
-import { DynamicFragment, type VaporFragment } from './block'
+import { DynamicFragment, type VaporFragment, insert } from './block'
import { createComponentWithFallback } from './component'
import { renderEffect } from './renderEffect'
import type { RawProps } from './componentProps'
import type { RawSlots } from './componentSlots'
+import {
+ insertionAnchor,
+ insertionParent,
+ resetInsertionState,
+} from './insertionState'
+import { isHydrating, locateHydrationNode } from './dom/hydration'
export function createDynamicComponent(
getter: () => any,
rawSlots?: RawSlots | null,
isSingleRoot?: boolean,
): VaporFragment {
+ const _insertionParent = insertionParent
+ const _insertionAnchor = insertionAnchor
+ if (isHydrating) {
+ locateHydrationNode()
+ } else {
+ resetInsertionState()
+ }
+
const frag = __DEV__
? new DynamicFragment('dynamic-component')
: new DynamicFragment()
+
renderEffect(() => {
const value = getter()
frag.update(
value,
)
})
+
+ if (!isHydrating && _insertionParent) {
+ insert(frag, _insertionParent, _insertionAnchor)
+ }
+
return frag
}