expect(html()).toBe('<baz></baz><!--dynamic-component-->')
})
+ test('with v-once', async () => {
+ const val = shallowRef<any>(A)
+
+ const { html } = define({
+ setup() {
+ return createDynamicComponent(() => val.value, null, null, true, true)
+ },
+ }).render()
+
+ expect(html()).toBe('AAA<!--dynamic-component-->')
+
+ val.value = B
+ await nextTick()
+ expect(html()).toBe('AAA<!--dynamic-component-->') // still AAA
+ })
+
+ test('fallback with v-once', async () => {
+ const val = shallowRef<any>('button')
+ const id = ref(0)
+ const { html } = define({
+ setup() {
+ return createDynamicComponent(
+ () => val.value,
+ { id: () => id.value },
+ null,
+ true,
+ true,
+ )
+ },
+ }).render()
+
+ expect(html()).toBe('<button id="0"></button><!--dynamic-component-->')
+
+ id.value++
+ await nextTick()
+ expect(html()).toBe('<button id="0"></button><!--dynamic-component-->')
+ })
++
+ test('render fallback with insertionState', async () => {
+ const { html, mount } = define({
+ setup() {
+ const html = ref('hi')
+ const n1 = template('<div></div>', true)() as any
+ setInsertionState(n1)
+ const n0 = createComponentWithFallback(
+ resolveDynamicComponent('button') as any,
+ ) as any
+ renderEffect(() => setHtml(n0, html.value))
+ return n1
+ },
+ }).create()
+
+ 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>')
+ })
})
rawProps?: RawProps | null,
rawSlots?: RawSlots | null,
isSingleRoot?: boolean,
+ once?: boolean,
): VaporFragment {
+ const _insertionParent = insertionParent
+ const _insertionAnchor = insertionAnchor
+ if (isHydrating) {
+ locateHydrationNode()
+ } else {
+ resetInsertionState()
+ }
+
const frag = __DEV__
? new DynamicFragment('dynamic-component')
: new DynamicFragment()
),
value,
)
- })
+ }
+
+ if (once) renderFn()
+ else renderEffect(renderFn)
+ if (!isHydrating && _insertionParent) {
+ insert(frag, _insertionParent, _insertionAnchor)
+ }
+
return frag
}
rawProps?: LooseRawProps | null,
rawSlots?: LooseRawSlots | null,
isSingleRoot?: boolean,
+ once?: boolean,
): HTMLElement | VaporComponentInstance {
if (!isString(comp)) {
- return createComponent(comp, rawProps, rawSlots, isSingleRoot)
+ return createComponent(comp, rawProps, rawSlots, isSingleRoot, once)
}
+ const _insertionParent = insertionParent
+ const _insertionAnchor = insertionAnchor
+ if (isHydrating) {
+ locateHydrationNode()
+ } else {
+ resetInsertionState()
+ }
+
const el = document.createElement(comp)
// mark single root
;(el as any).$root = isSingleRoot
validateProps,
warn,
} from '@vue/runtime-dom'
+ import { ReactiveFlags } from '@vue/reactivity'
import { normalizeEmitsOptions } from './componentEmits'
import { renderEffect } from './renderEffect'
+import { pauseTracking, resetTracking } from '@vue/reactivity'
export type RawProps = Record<string, () => unknown> & {
// generated by compiler for :[key]="x" or v-bind="x"