Skip to content

useComputed

在组件中动态创建计算属性并直接返回其值的 Hook。

与在状态树中预先声明计算属性不同,useComputed创建的计算属性是"游离"的——不写入状态树,仅存在于组件内部,组件卸载时自动销毁。

签名

ts
interface UseComputedType<State extends Dict> {
    // getter 函数(同步或异步)
    <Value>(getter: ComputedGetter<Value, Scope> | AsyncComputedGetter<Value, Scope>,
        computedOptions?: ComputedOptions<Value, Scope>
    ): AsyncComputedValue<Value>;
    // builder:如 computed(...) / asyncComputed(...) 声明
    <Value, Scope>(builder: ComputedDescriptorBuilder<Value, Scope>,
        computedOptions?: ComputedOptions<Value, Scope>
    ): AsyncComputedValue<Value>;
}

参数:

参数 说明
getter 计算函数,自动收集依赖;支持 async 函数
builder computed(...)asyncComputed(...)声明的描述符 builder
computedOptions 计算选项,见计算选项

返回值: AsyncComputedValue<Value>形态的对象({ value, loading, error, retry, timeout, progress, ... }),依赖变化时自动重新计算并触发重渲染。

使用说明

  • 适合组件私有的派生数据:不想污染全局状态树,又需要计算属性的特性(依赖追踪、异步能力)。
  • 内部基于useComputedObject实现,等价于useComputedObject(...)后再订阅其值变化。
  • 动态创建的计算属性默认挂载到根作用域(scope: ObserverScopeRef.Root),getter 的scope参数即整个状态树。
  • 返回值统一为AsyncComputedValue形态:同步计算时loading恒为false,直接使用value即可。

示例

tsx
const { useComputed } = createStore({
    order: { price: 100, count: 2 },
});

// 同步计算
const total = useComputed((state) => state.order.price * state.order.count);
// total.value

// 异步计算:声明式 builder
const discount = useComputed(
    asyncComputed(
        async (state) => {
            await delay(1000);
            return state.order.total * 0.8;
        },
        ['order.total'],
        { initial: 0.9 },
    ),
);
// discount.value / discount.loading / discount.error

运行效果如下:

loading

注意事项

每次渲染参数需保持稳定

计算属性对象仅在首次渲染时创建(内部useRef缓存)。请确保传入的 getter/builder 引用稳定,推荐在组件外定义 builder(如asyncComputed(...)),或使用useMemo包裹,避免依赖变化后计算属性不更新的困惑。

与 useReactive(getter) 的区别

useReactive((state) => ...)返回的是纯值,适合简单派生;useComputed返回完整计算属性对象,拥有loading/error/retry/run等能力,适合异步计算和需要手动控制的场景。