$ / signal 信号组件
信号组件将渲染更新限制在尽可能小的范围内:仅当所依赖的状态变化时,才重新渲染该片段,而不重渲染整个组件。
$与signal是同一个函数的两个名字(store.$ === store.signal)。
签名
ts
interface SignalComponentType<State extends Dict> {
// 1. 封装单个状态:$(path)
(selector: ObjectKeyPaths<ComputedState<State>>,
options?: SignalComponentOptions
): React.ReactNode;
// 2. 组合多个状态:$((state) => ReactNode)
(selector: (state: ComputedState<State>) => React.ReactNode,
options?: SignalComponentOptions
): React.ReactNode;
// 3. 自定义渲染 + 路径
<Value>(render: (value) => ReactNode,
path: string | string[],
options?: SignalComponentOptions
): React.ReactNode;
// 4. 自定义渲染 + getter(同步/异步)
<Value, Scope>(render: (value) => ReactNode,
getter: ComputedGetter<Value, Scope> | AsyncComputedGetter<Value, Scope>,
options?: SignalComponentOptions
): React.ReactNode;
// 5. 自定义渲染 + builder(computed(...)/asyncComputed(...))
<Value, Scope>(render: (value) => ReactNode,
builder: ObserverDescriptorBuilder<string, Value, Scope>,
options?: SignalComponentOptions
): React.ReactNode;
}选项(SignalComponentOptions):
| 选项 | 类型 | 说明 |
|---|---|---|
errorBoundary | ComponentType<{ error: any }> | 渲染出错时的兜底组件 |
自定义渲染函数参数: render(value)的value为AsyncComputedValue<Value>形态({ value, loading, error, timeout, retry, progress, ... }),可在渲染中直接使用loading/error等状态。
使用说明
$(path):最简形式,直接渲染路径的值。$((state) => ...):组合多个状态,自动收集渲染函数内访问的路径作为依赖。$(render, path/getter/builder):需要异步能力(loading/retry/timeout)或复杂渲染逻辑时使用;信号组件内部动态创建计算属性,生命周期随组件。
示例
tsx
const { state, $ } = createStore({
user: {
firstName: 'Zhang',
lastName: 'Fisher',
age: 18,
fullName: (user) => user.firstName + ' ' + user.lastName,
},
});
// 封装单个状态
<div>{$('user.age')}</div>
// 组合多个状态
<div>{(state) => state.user.firstName + ' ' + state.user.lastName}</div>
// 自定义渲染 + 异步计算
$(
({ loading, value }) => (loading ? '加载中...' : value),
asyncComputed(async () => { /* ... */ }, ['user.age'], { initial: 0 }),
)运行效果如下:
loading
自定义渲染异步计算:
loading
更多用法参见信号组件指南。
注意事项
signal 内部是独立渲染单元
信号组件渲染的是独立的 React 子树,其依赖变化只重渲染该子树,外层组件不会重渲染。不要在信号组件的渲染函数中引用会随外层变化的闭包变量——它们不会触发信号更新。
与 useReactive 的选择
渲染局部一小片值(如表格单元格、价格标签)用$();需要在组件逻辑中读写值(事件处理、条件分支)用useReactive。两者可混用。