Dynamic
Dynamic 是动态视图构建器,用于根据条件动态渲染不同的组件或 HTML 元素。当渲染目标发生变化时,Dynamic 会自动切换渲染内容。
基本用法
动态组件
tsx
import { Dynamic, shallowRef } from 'vitarx'
function ComponentA() {
return <div>组件 A</div>
}
function ComponentB() {
return <div>组件 B</div>
}
function App() {
const current = shallowRef(ComponentA)
return (
<div>
<button
onClick={() => {
current.value = ComponentA
}}
>
显示 A
</button>
<button
onClick={() => {
current.value = ComponentB
}}
>
显示 B
</button>
{/* 动态渲染 current 指向的组件 */}
<Dynamic is={current} />
</div>
)
}动态 HTML 标签
Dynamic 也可以动态渲染不同的 HTML 标签:
tsx
import { Dynamic, shallowRef } from 'vitarx'
function App() {
const tag = shallowRef<'div' | 'span' | 'p'>('div')
return (
<div>
<button
onClick={() => {
tag.value = 'div'
}}
>
div
</button>
<button
onClick={() => {
tag.value = 'span'
}}
>
span
</button>
<button
onClick={() => {
tag.value = 'p'
}}
>
p
</button>
{/* 动态渲染不同的 HTML 标签 */}
<Dynamic is={tag}>这段内容的标签会变化</Dynamic>
</div>
)
}传递属性
Dynamic 上除 is、key、memo、children 以外的属性,都会原样传递给渲染的组件或元素:
tsx
<Dynamic is={current} title="hello" className="active" />属性
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
is | Component | HostElementTag | Ref<any> | undefined | null | false | 是 | 动态渲染目标 |
key | unknown | 否 | 唯一标识,配合 memo 缓存同一组件的不同实例 |
memo | boolean | number | 否 | 缓存策略,默认 false 不缓存 |
children | RenderChildren | 否 | 子节点,传递给动态组件或元素 |
...其他属性 | any | 否 | 其他属性会原样传递给渲染的组件或元素 |
memo — 缓存策略
Dynamic 默认不缓存切换掉的组件视图。如果你希望切换后再切回来时复用之前的视图,可以开启 memo:
| memo 值 | 行为 |
|---|---|
false(默认) | 不缓存,切换时销毁旧视图 |
true | 缓存所有组件视图,不限制数量 |
number > 0 | 缓存指定数量的组件视图,采用 LRU 策略淘汰 |
number <= 0 | 等同于 true,不限制数量 |
注意:
memo仅对组件函数有效,HTML 标签不会被缓存。如果你需要更完整的缓存功能(如include/exclude),请使用 Freeze 组件。
tsx
import { Dynamic, shallowRef } from 'vitarx'
function PageA() {
return <div>页面 A</div>
}
function PageB() {
return <div>页面 B</div>
}
function PageC() {
return <div>页面 C</div>
}
function App() {
const current = shallowRef(PageA)
return (
// 最多缓存 3 个组件视图
<Dynamic is={current} memo={3} />
)
}Dynamic 与 Freeze 的区别
| 特性 | Dynamic | Freeze |
|---|---|---|
| 缓存策略 | 简单的 memo 缓存 | 完整的缓存管理(include/exclude/max) |
| 组件冻结 | 切换时销毁或缓存 | 切换时冻结响应式,保留完整状态 |
| 适用场景 | 简单的动态渲染 | 需要保留组件状态的 Tab 页签等 |
| HTML 标签 | 支持 | 不支持 |
简单来说:如果只是动态切换组件,用 Dynamic;如果需要保留组件状态,用 Freeze。
完整示例
下面是一个使用 Dynamic 实现动态表单的完整示例:
tsx
import { Dynamic, shallowRef, ref } from 'vitarx'
/** 文本输入表单 */
function TextForm() {
const value = ref('')
return (
<div>
<h3>文本输入</h3>
<input
value={value}
onInput={(e) => {
value.value = (e.target as HTMLInputElement).value
}}
placeholder="请输入文本"
/>
<p>当前值:{value}</p>
</div>
)
}
/** 数字输入表单 */
function NumberForm() {
const value = ref(0)
return (
<div>
<h3>数字输入</h3>
<input
type="number"
value={value}
onInput={(e) => {
value.value = Number((e.target as HTMLInputElement).value)
}}
/>
<p>当前值:{value}</p>
</div>
)
}
/** 选择表单 */
function SelectForm() {
const value = ref('apple')
return (
<div>
<h3>选择</h3>
<select
value={value}
onChange={(e) => {
value.value = (e.target as HTMLSelectElement).value
}}
>
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橘子</option>
</select>
<p>当前选择:{value}</p>
</div>
)
}
function App() {
const formTypes = [
{ label: '文本', component: TextForm },
{ label: '数字', component: NumberForm },
{ label: '选择', component: SelectForm }
]
const current = shallowRef(TextForm)
return (
<div>
<h2>动态表单</h2>
<div style="margin-bottom: 16px;">
{formTypes.map((item) => (
<button
key={item.label}
onClick={() => {
current.value = item.component
}}
style={{
marginRight: '8px',
fontWeight: current.value === item.component ? 'bold' : 'normal'
}}
>
{item.label}
</button>
))}
</div>
{/* 动态渲染当前选中的表单组件 */}
<Dynamic is={current} />
</div>
)
}下一步
- Freeze — 组件缓存,保留组件状态
- Lazy 与 lazy — 懒加载组件
- Transition — 过渡动画