Vue 状态管理:Vuex 与 Pinia
阶段一:评估需求与确定技术栈
- 核对 当前项目使用的 Vue 框架版本。Vue 3 项目默认推荐
Pinia;Vue 2 项目若未启用 Composition API 组合式 API,继续使用Vuex 3.x即可。 - 评估 跨组件通信的复杂度。仅涉及简单父子传值或基础配置读取时,直接使用 Vue 内置的
provide提供与inject注入;涉及复杂业务流、全局拦截或大型团队协作时,引入 独立状态管理库。 - 查阅 团队现有技术规范。若项目已存在大量
Vuex模块且维护成本可控,保留 现有架构;新建模块或重构旧代码时,优先选择Pinia,因其原生支持类型推断、打包体积更小且无需嵌套Mutation修改数据。
| 特性维度 | Vuex | Pinia |
|---|---|---|
| 核心架构 | 单一全局 Store 树 + 嵌套 Module 模块 | 扁平化独立 Store 实例设计 |
| 数据修改路径 | 强制通过 Mutation 同步提交,Action 处理异步请求 |
直接在 Action 中修改,彻底取消 Mutation 概念 |
| 类型推断支持 | 需额外安装插件或手动定义复杂接口声明 | 完整支持 TypeScript,函数调用即可自动推导类型 |
| 核心打包体积 | 约 11 KB(Gzip 压缩后) |
约 1 KB(Gzip 压缩后) |
阶段二:安装与初始化项目
- 打开 终端或命令行窗口,切换 至前端项目根目录。
- 执行 包管理器安装命令。若确定使用
Pinia,输入npm install pinia;若维持Vuex体系,输入npm install vuex@next以适配 Vue 3。 - 创建 状态库入口目录。在项目
src文件夹下 新建 名为store的目录,并在其内部 生成 文件index.js。 - 编写 根应用挂载逻辑。打开
src/main.js,导入 状态库创建函数并 注册 至 Vue 实例。以Pinia为例:import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
若使用 `Vuex`,需替换为 `import { createStore } from 'vuex'`,并将 `createPinia()` 替换为 `createStore({ state: {}, mutations: {} })`,**调用** `app.use()` 传入实例对象。
---
## 阶段三:编写状态管理核心逻辑
1. **定义** 独立状态模块。进入 `src/store` 目录,**新建** 业务文件 `userStore.js`。
2. **初始化** Store 实例结构。`Pinia` 采用组合式函数 API,**调用** `defineStore` 并传入唯一标识符 `id`、响应式状态 `state` 与操作方法:
```javascript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserStore = defineStore('user', () => {
// 定义响应式状态
const userInfo = ref({ name: '', token: '', role: '' })
// 定义派生状态(计算属性)
const isLoggedIn = computed(() => Boolean(userInfo.value.token))
// 定义同步与异步操作
async function fetchProfile() {
const response = await fetch('/api/me')
const data = await response.json()
userInfo.value = data
}
function clearSession() {
userInfo.value = { name: '', token: '', role: '' }
}
return { userInfo, isLoggedIn, fetchProfile, clearSession }
})
- 编写
Vuex等效实现。若项目强制使用Vuex,必须严格拆分同步与异步层:import { createStore } from 'vuex'
export const userModule = {
namespaced: true,
state: () => ({
userInfo: { name: '', token: '' }
}),
mutations: {
updateProfile(state, payload) {
state.userInfo = payload
}
},
actions: {
async fetchProfile({ commit }) {
const res = await fetch('/api/me')
const data = await res.json()
commit('updateProfile', data)
}
},
getters: {
isLoggedIn: (state) => !!state.userInfo.token
}
}
4. **合并** 模块至主入口。在 `src/store/index.js` 中 **导入** 刚定义的模块,**导出** 统一状态树配置。
---
## 阶段四:在组件中调用与监听状态
1. **打开** 需要消费全局状态的 Vue 单文件组件(如 `src/views/Home.vue`)。
2. **导入** 状态函数。在 `<script setup>` 标签顶部 **添加** 引用语句:`import { useUserStore } from '@/store/userStore.js'`。
3. **实例化** Store 对象。在组件顶层作用域内 **调用** 函数并 **接收** 返回值:`const userStore = useUserStore()`。注意:必须在 `setup` 语法环境或组件生命周期内调用,**禁止** 在外部 JS 文件中全局调用。
4. **读取** 响应式数据。在模板 `{{ }}` 插值表达式中 **直接使用** `userStore.userInfo.name`;在 `<script>` 逻辑中 **绑定** `userStore.isLoggedIn` 控制条件渲染。
5. **触发** 状态更新。为交互元素(如按钮或表单)**绑定** 事件回调,**执行** 异步请求方法:`userStore.fetchProfile()`。若使用 `Vuex`,需通过 `import { useStore } from 'vuex'` 获取根实例,并 **调用** `store.dispatch('user/fetchProfile')`。
6. **监听** 数据流转。在 `<script setup>` 中 **引入** Vue 的监听器:`import { watch } from 'vue'`,并 **配置** 响应式观测:
```javascript
watch(() => userStore.isLoggedIn, (isLogged, wasLogged) => {
if (isLogged && !wasLogged) {
// 执行登录成功后的路由跳转或埋点逻辑
}
})
阶段五:调试追踪与持久化配置
- 启用 官方浏览器调试工具。访问 Chrome 或 Edge 扩展商店,搜索
Vue.js devtools并完成插件安装。 - 捕获 状态变更轨迹。刷新目标页面,按
F12调出开发者面板,切换 至Vue专属选项卡。在左侧面板 点击Pinia或Vuex分类,右侧视图将渲染当前全局状态快照树。 - 回溯 历史数据版本。在插件时间轴控件上 点击 任意灰色节点,验证 页面数据是否精准还原至该节点记录时刻。测试完毕后,拖动 滑块至最右侧恢复实时状态。
- 拆分 巨型状态文件。当单个模块逻辑行数突破 300 行时,采用 组合策略将购物车、权限、主题等子状态抽离为独立
.js文件,并在index.js中统一聚合导出。 - 挂载 本地持久化插件。若需在页面刷新后保留登录态或用户偏好,运行
npm install pinia-plugin-persistedstate,修改src/main.js注册流程:import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
在状态定义中 **附加** 配置项,于 `defineStore` 返回值平级 **添加** `__persist: true` 或完整对象 `{ key: 'app-user', storage: sessionStorage }`,**指定** 浏览器存储引擎。
暂无评论,快来抢沙发吧!