Pinia 的 state 默认响应式,无需手动 reactive;应拆分为语义化子模块,避免巨型 state;用 interface 明确类型,必要时结合 computed + reactive 封装独立响应式对象。

Pinia 本身已经基于 reactive 构建,它的 state 默认就是响应式对象——所以你不需要手动用 reactive 套一层再塞进 Pinia。真正要关注的是:如何合理组织“全局业务大对象”,避免它变成难以维护的巨型 state,同时保持类型清晰、更新可控、逻辑可测。
别把 reactive 当 glue,Pinia 的 state 就是 reactive
很多人误以为“要用 reactive 管理大对象,就得先 new 一个 reactive,再 assign 给 store”。这是多余的。Pinia 的 state: () => ({ ... }) 内部会自动调用 reactive() 包装返回的对象,所有嵌套属性天然响应式。比如:
- 用户资料模块含 profile、permissions、preferences 三层嵌套?直接写在 state 里,不用额外 reactive
- 订单列表带分页、筛选条件、loading 状态?统一归入 state,Pinia 自动处理响应性
- 需要 deep watch 某个字段?用
watch(() => store.orderForm, ...)即可,无需自己转 reactive
拆解“大对象”为语义化子模块,而非堆在一个 state 里
所谓“业务大对象”,往往不是单个数据结构,而是多个职责耦合的集合。Pinia 推荐扁平化模块设计,而不是在单个 store 里塞一个巨型对象。例如:
Orderly React SDK 钩子使用参考指南,包括 useOrderEntry、usePositionStream、useOrderbookStream、useCollateral 等。
- 不要写
useBusinessStore()管理“全部业务数据”,而应拆成useUserStore()、useOrderStore()、useProductStore() - 每个 store 聚焦单一领域,state 只保留该领域核心字段,避免
state.allTheThings = { user: {}, order: {}, config: {} }这类反模式 - 跨 store 关联用
getters或actions中调用其他 store,而不是把所有数据都塞进一个对象里
对复杂嵌套结构,用 interface + 类型守卫提升可维护性
当某个字段确实是大型嵌套对象(如完整的表单 schema、动态配置树),建议显式定义 TypeScript 接口,并在初始化时做轻量校验:
立即学习“前端免费学习笔记(深入)”;
- 用
interface FormConfig { fields: FieldItem[]; rules: Record<string, string>; }明确结构 - state 初始化写成
formConfig: () => ({ fields: [], rules: {} } as FormConfig),保证类型推导完整 - 必要时在 action 中加
if (!config?.fields) return防错,比 runtime 报Cannot read property 'map' of undefined更友好
需要深度响应但又不想污染 store?用 computed + reactive 组合封装
极少数场景下,你确实需要独立于 store 的响应式大对象(比如第三方 SDK 的配置实例、Canvas 渲染状态),这时可以:
- 在 store 的
actions里创建:this.canvasState = reactive({ zoom: 1, panX: 0, panY: 0 }) - 或在 setup 中用
const canvasState = reactive({...}),再通过store.$patch或自定义事件同步关键字段到 store - 不推荐直接把整个
reactive(...)对象挂到 state 属性上,会导致 devtools 调试困难、序列化异常

















