Vuex 是 Vue 2 时代官方提供的状态管理库,它采用单一状态树和显式同步/异步分离的设计,将应用中的所有组件共享状态集中管理。尽管 Pinia 已经成为 Vue 3 的官方推荐方案,理解 Vuex 的核心概念仍然很有必要——很多存量项目仍在使用,而且 Pinia 本身就是对 Vuex 设计思想的演进和简化。
State:全局数据的唯一真相源
State 就是存储在 Vuex 中的一个响应式对象,整个应用仅有一个 Store 实例,所有组件都从这里读取数据。
// Vuex Store 定义
const store = createStore({
state: {
user: null,
token: ''
}
})
// 组件中通过计算属性读取
computed: {
user() {
return this.$store.state.user
}
}
- 确保数据唯一:与组件内部状态不同,State 里的数据可在任意组件中访问,避免了“各自维护一份副本”导致的同步问题。
- 严格模式:Vuex 可以开启严格模式,在开发环境下,任何直接修改 State(非通过 Mutation)的行为都会报错,从机制上保证了数据流的可追溯性。
Getters:Store 的计算属性
Getters 用于从 State 中派生出新的状态,类似于 Vue 组件内的 computed。当多个组件需要同样的计算逻辑时,放在 Getters 中可以避免重复编码,并且自动缓存结果。
const store = createStore({
state: {
cart: [{ id: 1, price: 100, qty: 2 }]
},
getters: {
cartTotal(state) {
return state.cart.reduce((sum, item) => sum + item.price * item.qty, 0)
}
}
})
// 组件使用
computed: {
total() {
return this.$store.getters.cartTotal
}
}
Mutations:唯一允许修改 State 的同步方法
Mutations 是 Vuex 中唯一能修改 State 的入口,且必须是同步函数。这种限制不是麻烦,而是一种数据流向的纪律:每一次状态变更都有明确的记录,方便调试和回放。
// 定义 Mutation
mutations: {
SET_USER(state, payload) {
state.user = payload
}
}
// 组件中提交 Mutation
this.$store.commit('SET_USER', { name: 'Alice' })
- 可追踪:Vue DevTools 会记录每一次 Mutation 的快照,你可以像操作 Git 一样检查状态的变更历史。
- 约定纯同步:异步操作必须放在 Actions 中,保证 Mutation 的可预测性。
Actions:处理异步操作和业务逻辑
Actions 用来封装异步请求(如 API 调用)和包含多条 Mutation 的复合逻辑。它不直接修改 State,而是通过 commit 触发 Mutations 来完成状态更新。
actions: {
async login({ commit }, credentials) {
const user = await api.login(credentials)
commit('SET_USER', user)
return user
}
}
// 组件中分发 Action
this.$store.dispatch('login', { email, password })
- 可以在一个 Action 中提交多个 Mutation,执行完一步再下一步。
- 支持 async/await,可以链式返回 Promise,方便组件在 Action 完成后执行后续操作(比如跳转页、弹窗提示)。
Modules:大型 Store 的模块化拆分
当应用庞大到 State、Mutations、Actions 都挤在一个对象里时,维护会变得困难。Modules 允许将 Store 拆分成多个子模块,每个模块拥有自己的 State、Getters、Mutations 和 Actions。
const moduleA = {
state: () => ({ list: [] }),
mutations: { ADD_ITEM(state, item) { state.list.push(item) } },
actions: { ... },
getters: { ... }
}
const store = createStore({
modules: {
a: moduleA
}
})
- 命名空间:默认模块的 State 是分离的,但 Getters、Mutations 和 Actions 会注册到全局。推荐使用
namespaced: true开启模块命名空间,避免方法名冲突。 - 动态注册:可以在运行时使用
store.registerModule动态添加模块,适合按需加载的场景。
对比 Pinia:Vuex 的核心概念如何被简化
在 Pinia 中,这些概念被大幅精简:
- 不再有 Mutations:Pinia 认为强制区分同步/异步增加了编码成本,因此允许在 Actions 中直接修改 State,也允许在组件中直接调用
store.xxx = value。开发体验更接近“直接改数据”,同时依然保持 DevTools 和时间旅行调试的支持。 - 去除了 Modules 的嵌套树:每个 Store 天生就是一个模块,通过引入不同的 Store 文件实现逻辑拆分,不再需要冗长的模块注册,也不再需要记忆
rootState和局部命名空间。 - 完整的 TypeScript 支持:Pinia 从设计之初就以 TypeScript 为优先,类型推导非常完整,而 Vuex 在使用 TS 时往往需要繁重的类型声明。
一句话总结:Vuex 通过 State、Getters、Mutations、Actions、Modules 这五个概念,为大型应用构建了一条清晰、可管控的数据流向;而 Pinia 则在保留 Vuex 所有调试能力的基础上,去掉了 Mutations 和 Modules 的复杂性,让状态管理的代码更贴近“直接修改 JS 对象”的直觉体验。如果你是新项目,直接选择 Pinia 即可;如果仍在维护 Vuex 项目,理解这些概念就能轻松驾驭现有代码。