store 是 pinia 状态管理的基石,需语义化命名(如 useuserstore)、采用 setup api 风格、state 必为函数返回对象、按功能单一职责拆分模块,并在 typescript 中显式标注类型以保障类型安全与协作可靠性。

定义 Store 是 Pinia 使用的第一步,也是整个状态管理结构的基石。关键不在于“怎么写出来”,而在于“怎么设计得清晰、可维护、易协作”。
Store 名字要明确且唯一
名字是 Pinia 识别和调试 Store 的唯一标识,必须全局唯一,且建议用语义化名词(如 user、cart、workflow),避免泛称如 data 或 global。
命名习惯统一用 useXxxStore,比如:
export const useUserStore = defineStore('user', { /* ... */ })
export const useCartStore = defineStore('cart', { /* ... */ })
这个名字会直接出现在 Vue Devtools 中,也用于 SSR 和插件集成,不能随意改动。
优先选用组合式 API(Setup Store)
Setup Store 更贴近 Vue3 的 Composition API 风格,支持 ref、computed、watch 等组合式函数,逻辑组织更自然:
-
ref→ 对应 state -
computed→ 对应 getters - 普通函数 → 对应 actions
示例:
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
function reset() {
count.value = 0
}
return { count, doubleCount, increment, reset }
})
注意:所有需要暴露给组件使用的响应式变量和函数,都必须显式 return,否则无法访问。
State 必须是函数返回对象
无论用 Option 还是 Setup 方式,state 必须是函数(() => ({})),这是为了确保每次实例化 Store 时获得独立的响应式副本,避免服务端渲染或多实例场景下的状态污染。
// ✅ 正确
state: () => ({ count: 0, list: [] })
// ❌ 错误(会导致多个组件共享同一对象)
state: { count: 0, list: [] }
模块职责要单一,按功能边界拆分
一个 Store 应只管理一个业务域的状态,比如:
- 用户相关 →
useUserStore - 购物车 →
useCartStore - 工作流 →
useWorkflowStore
避免把所有状态塞进一个 useAppStore。模块过多时,可进一步按子域组织(如 user/profile、user/permission),但通常一级划分已足够。
类型安全从定义开始
TypeScript 下,强烈建议为 state 显式标注类型,尤其在复杂对象场景:
interface UserState {
id: number | null
name: string
token: string | null
roles: string[]
}
export const useUserStore = defineStore('user', () => {
const state = reactive<userstate>({
id: null,
name: '',
token: null,
roles: []
})
// ...
})</userstate>
Pinia 本身能自动推导类型,但显式接口让重构和团队协作更可靠。
不复杂但容易忽略










