pinia 的 composition store 是状态容器而非逻辑单元,真正复用逻辑靠组合式函数(composables)封装流程并调用 store;store 只负责原子状态管理,复杂行为应交由 composable 处理。

Pinia 的 composition store 本身不直接“复用逻辑”,而是提供可复用的状态容器;真正实现跨组件逻辑复用的,是把业务流程封装在组合式函数(composables)里,并在其中调用 store —— 这才是官方推荐、工程实践中最清晰的分工方式。
composition store 的本质是状态容器,不是逻辑单元
defineStore 返回的 store 是一个响应式对象,它管理 state、getters 和 actions,但不负责控制流程、处理副作用或协调多个 API 调用。它的职责很明确:存什么、怎么算、怎么改。如果你把表单提交校验、错误重试、loading 状态联动、权限拦截等都写进 store 的 action 里,很快就会让 store 变得臃肿且难以测试。
正确做法是:
- store 只暴露原子能力:比如
login(credentials)只负责发请求并更新 token 和 profile - 复杂流程交给 composables:比如
useLoginForm()内部调用userStore.login(),再整合校验、防重复提交、错误提示等 - 组件只消费结果:从 store 拿
isAuthenticated,从 composable 拿submit和errors
跨组件复用逻辑的典型路径
假设你有登录弹窗、侧边栏用户菜单、首页欢迎语三个地方都需要“检查登录态 + 点击跳转登录”逻辑:
- 在
stores/auth.ts中定义useAuthStore:专注维护token、user、login()、logout() - 在
composables/useAuthFlow.ts中封装逻辑:
→ 监听isAuthenticated响应式变化
→ 提供redirectToLogin(redirectPath?)
→ 自动保存来源页、跳转后还原 - 各组件分别 import:
const authStore = useAuthStore()const { redirectToLogin } = useAuthFlow()
这样,状态统一由 store 管理,行为逻辑由 composable 复用,组件保持轻量、职责单一。
避免常见陷阱:别让 store 变成“万能胶”
以下写法看似方便,实则破坏可维护性:
- 在 store 的 action 里直接调用
router.push()或ElMessage.error():耦合了路由和 UI 库,无法在无界面环境(如 SSR、测试)中运行 - 把
useFetch封装进 store:fetch 逻辑应该独立可测,store 只接收数据并更新 state - 多个 store 互相调用(A store 的 action 调 B store 的 action):形成隐式依赖,调试困难,模块边界模糊
真正解耦的方式是:composable 负责串联,store 负责提供数据契约。
进阶技巧:用 store 组合函数提升模块复用性
Pinia 支持在 defineStore 内部调用其他 store,适合构建“状态层插件”。例如:
- 写一个
createCachedApiStore工厂函数,接受 URL 和缓存策略,返回带data、fetch()、invalidate()的 store - 多个业务 store(如
useProductStore、useOrderStore)都基于它创建,共享缓存逻辑但隔离数据域 - 这种模式适合通用能力抽象,但不替代 composables 对业务流程的封装










