前言
在构建中大型 Vue 单页应用时,组件间的通信往往会变得复杂。Vuex 作为一个专为 Vue.js 应用程序开发的状态管理模式 + 库,采用集中式存储管理应用的所有组件的状态。本文将带你从核心概念到持久化方案,深度拆解 Vuex 的运行机制。
一、 为什么需要 Vuex?
1. 核心概念
Vuex 采用全局单例模式,将组件的共享状态抽取出来进行管理。它解决了以下两大痛点:
- 多视图依赖同一状态:如用户信息在头部、侧边栏、个人中心都需要显示。
- 不同视图的行为需要修改同一状态:如购物车在不同页面进行增删改查。
2. 单向数据流约束
Vuex 规定:组件可以读取 State,但严禁直接修改 State。这种约束确保了状态变更的可预测性和可追溯性。
二、 五大核心模块
1. State(全局仓库)
存储数据的唯一数据源,类似于组件的 data,只可以读,不能进行写操作。
2. Getters(加工厂)
有些时候我们需要对获取的数据进行加工,获取数据的一部分或者某些属性,而不是直接获取state中的数据时,这时候可以通过getter定义函数,返回对应的数据。
3. Mutations(状态变更)
唯一能修改 State 的地方,在vue组件中可以通过commit触发修改函数。不过mutations里面的操作必须是同步的。
4. Actions(异步中转)
用于处理异步逻辑(如 API 请求),通过提交 (commit) Mutation 来间接修改 State。
5. Modules(模块化)
当 Store 对象变得臃肿时,可以将其拆分为多个子模块,每个模块拥有独立的五大核心概念。
三、 使用示例:
Store 定义 (store/index.ts):
import { createStore, ActionContext } from 'vuex'
// 1. 定义 State 类型
interface PersonalInfo {
name: string
age: number
}
interface State {
personalInfo: PersonalInfo
}
export default createStore<State>({
state: {
personalInfo: {
name: "Liu",
age: 27
}
},
// 同步修改数据
mutations: {
CHANGE_INFO_NAME(state) {
state.personalInfo.name = "Rick"
}
},
// 异步触发逻辑
actions: {
// context 参数具有和 Store 实例相同的属性和方法
asyncUpdateInfo(context: ActionContext<State, State>) {
setTimeout(() => {
context.commit("CHANGE_INFO_NAME")
}, 1000)
}
}
})
组件调用:
<script setup lang="ts">
import { useStore } from 'vuex'
const store = useStore()
const change = () => {
// 触发 Mutation (同步)
// store.commit("CHANGE_INFO_NAME")
// 触发 Action (异步)
store.dispatch("asyncUpdateInfo")
}
</script>
<template>
<div>
<p>姓名:{{ store.state.personalInfo.name }}</p>
<button @click="change">异步修改名称</button>
</div>
</template>
四、 核心面试题
1. 为什么 Mutation 必须是同步的?
这是为了状态追踪。在 Vue Devtools 中,每当 Mutation 被提交,插件都会捕捉到前后的快照。如果是异步的,回调函数执行时 Mutation 已经结束,Devtools 无法追踪到状态到底是什么时候变化的,这会让调试变得极其困难。
2. Mutation vs Action 有什么区别?
| 特性 | Mutation | Action |
|---|---|---|
| 操作性质 | 同步操作 | 异步/同步均可 |
| 职责 | 唯一直接修改 State 的地方 | 提交 Mutation,不直接操作 State |
| 参数 | 第一个参数是 state | 第一个参数是 context 对象 |
| 调用方式 | commit('name') | dispatch('name') |
五、 状态持久化与存储
由于 Vuex 的状态是存储在内存中的,刷新页面后数据会丢失。
- 解决方案:结合
localStorage或sessionStorage。 - 手动实现:在 Mutation 变更状态时同步写入本地存储;在页面加载(App.vue 的
created)时,从本地取出数据重新还原到 Store。 - 进阶工具:推荐使用
vuex-persistedstate插件,可以自动完成持久化同步工作。