出处:掘金
原作者:金泽宸
前端状态不是“能用就放 store”,而是“局部用局部管,模块用模块管,全局才上全局 store”
状态管理是前端架构中最容易“滥用”,却最影响维护性与性能的模块
在实际开发中,你是否遇到这些问题:
props 和 emit 层层传递,毫无乐趣本篇我们将:
将状态拆成 4 层:
| 层级 | 状态类型 | 举例 | 建议位置 |
|---|---|---|---|
| ① 页面状态 | 表单输入、分页、loading | formData、currentPage | 组件内部 / setup() |
| ② 业务状态 | 当前用户信息、购物车内容 | userInfo、cartList | 模块 store(Pinia) |
| ③ 全局状态 | 多模块共享、应用级别 | 主题、token、权限 | 全局 store |
| ④ 派发逻辑 | 状态之间的数据流 | A 模块更新后通知 B | EventBus / 中间 store / 联动处理 |
以 Vue3 + Pinia 为例
src/
├── modules/
│ └── user/
│ ├── views/...
│ ├── store.ts # 用户业务状态
│ ├── api.ts
├── store/ # 全局状态
│ ├── app.ts # 主题、语言
│ ├── auth.ts # 登录 token、权限列表
│ └── index.ts
示例:业务模块 store
// modules/user/store.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
info: null,
}),
actions: {
async fetch() {
this.info = await getUserInfo()
},
},
})
const formData = reactive({ name: '', age: '' })
// 不应放入 store
const authStore = useAuthStore()
const token = authStore.token
// 使用模块级 store:useGoodsStore()
onMounted 时恢复useRouteQuery(),在 query 中保持关键状态sessionStorage 临时保存页面缓存数据当模块 A 修改状态后,希望模块 B 响应更新,可以用:
// 在模块 B 中监听
userStore.$subscribe((mutation, state) => {
if (mutation.storeId === 'user' && mutation.events.key === 'info') {
console.log('用户信息变化了')
}
})
创建一个通用的 eventStore:
export const useEventStore = defineStore('event', {
state: () => ({ events: {} }),
actions: {
fire(event, payload) {
this.events[event] = payload
},
clear(event) {
delete this.events[event]
},
},
})
模块 A:
eventStore.fire('refresh-table', { force: true })
模块 B:
watch(() => eventStore.events['refresh-table'], (val) => {
if (val?.force) refreshTable()
})
如:持久登录 / 记住用户
使用 pinia-plugin-persistedstate 插件:
npm i pinia-plugin-persistedstate
在入口注册:
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPersist)
定义持久化字段:
export const useAuthStore = defineStore('auth', {
state: () => ({ token: '' }),
persist: true,
})
setup 内部 ref/reactive 管理storeuseUserStore、useAuthStore)useRouteQueryState():自动将分页等状态绑定到 URLusePersistedRef():封装 localStorage/SessionStorage 自动存取createScopedStore():为多 tab 设计私有状态pinia-auto-module:支持自动生成模块 + 动态加载 store