feat(runtime-vapor): add v-once support to createDynamicComponent

This commit is contained in:
daiwei 2025-06-10 16:30:51 +08:00
parent 9087cdf3cb
commit 0d81c0b854
3 changed files with 49 additions and 5 deletions

View File

@ -1,4 +1,4 @@
import { shallowRef } from '@vue/reactivity'
import { ref, shallowRef } from '@vue/reactivity'
import { nextTick } from '@vue/runtime-dom'
import { createDynamicComponent } from '../src'
import { makeRender } from './_utils'
@ -54,4 +54,42 @@ describe('api: createDynamicComponent', () => {
await nextTick()
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-->')
})
})

View File

@ -15,7 +15,8 @@ export function createDynamicComponent(
const frag = __DEV__
? new DynamicFragment('dynamic-component')
: new DynamicFragment()
renderEffect(() => {
const renderFn = () => {
const value = getter()
frag.update(
() =>
@ -28,6 +29,10 @@ export function createDynamicComponent(
),
value,
)
})
}
if (once) renderFn()
else renderEffect(renderFn)
return frag
}

View File

@ -479,9 +479,10 @@ export function createComponentWithFallback(
;(el as any).$root = isSingleRoot
if (rawProps) {
renderEffect(() => {
const setFn = () =>
setDynamicProps(el, [resolveDynamicProps(rawProps as RawProps)])
})
if (once) setFn()
else renderEffect(setFn)
}
if (rawSlots) {