Vuex 状态管理最佳实践指南

This commit is contained in:
bunny 2025-06-19 12:44:04 +08:00
parent 5546635e31
commit eb49928833
4 changed files with 228 additions and 15 deletions

View File

@ -1,12 +1,13 @@
import Vue from "vue"; import Vue from "vue";
import Vuex from "vuex"; import Vuex from "vuex";
import count from "./modules/count";
Vue.use(Vuex); Vue.use(Vuex);
const store = new Vuex.Store({ const store = new Vuex.Store({
state: {}, state: {},
mutations: {}, mutations: {},
actions: {}, actions: {},
modules: {}, modules: { count },
}); });
export default store; export default store;

View File

@ -0,0 +1,41 @@
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const count = {
namespaced: true,
state: { num: 1, sum: 0 },
actions: {
// 奇数相加
incrementOdd(context) {
// 可以从上下文中获取sum
if (context.state.sum % 2) {
context.commit("INCREMENT_ODD");
}
},
incrementWait(context) {
setTimeout(() => {
context.commit("INCREMENT_WAIT");
}, 500);
},
},
mutations: {
// 相加
INCREMENT(state) {
state.sum += state.num;
},
// 相减
DECREMENT(state) {
state.sum -= state.num;
},
// 奇数相加
INCREMENT_ODD(state) {
state.sum += state.num;
},
INCREMENT_WAIT(state) {
state.sum += state.num;
},
},
};
export default count;

View File

@ -0,0 +1,178 @@
# Vuex 状态管理最佳实践指南
## 一、核心架构解析
### 1. 模块化结构
```javascript
// store/index.js - 主入口文件
import count from './modules/count'
export default new Vuex.Store({
modules: {
count // 启用命名空间的计数模块
}
})
// store/modules/count.js - 计数模块
export default {
namespaced: true, // 启用命名空间
state: {
num: 1,
sum: 0
},
mutations: { /* 同步操作 */ },
actions: { /* 异步操作 */ }
}
```
### 2. 数据流示意图
```
组件 → dispatch → Actions → commit → Mutations → mutate → State → 响应式更新 → 组件
```
## 二、代码优化建议
### 1. 组件中的优化
```javascript
// 使用map辅助函数简化代码
import { mapActions, mapMutations, mapState } from 'vuex'
export default {
computed: {
...mapState('count', ['sum', 'num'])
},
methods: {
...mapMutations('count', ['INCREMENT', 'DECREMENT']),
...mapActions('count', ['incrementOdd', 'incrementWait'])
}
}
```
### 2. Store 中的优化
```javascript
// 使用常量替代字符串 mutation 类型
const types = {
INCREMENT: 'INCREMENT',
DECREMENT: 'DECREMENT'
}
const count = {
mutations: {
[types.INCREMENT](state) {
state.sum += state.num
}
}
}
```
## 三、最佳实践规范
### 1. 命名规范
| 类型 | 命名风格 | 示例 |
| -------- | ------------ | ----------------- |
| Mutation | 大写+下划线 | `INCREMENT` |
| Action | camelCase | `fetchData` |
| Getter | 形容词/名词 | `filteredList` |
| Module | 业务相关名词 | `user`, `product` |
### 2. 操作分离原则
- **Mutations**
- 只做简单状态赋值
- 必须是同步函数
- 命名类似事件(`SET_USER_INFO`
- **Actions**
- 处理业务逻辑
- 可以包含异步操作
- 命名类似方法(`fetchUserData`
### 3. 模块化建议
1. 按功能/业务划分模块
2. 每个模块启用命名空间
3. 模块内维护独立state
## 四、高级应用场景
### 1. 动态模块注册
```javascript
// 在需要时加载模块
store.registerModule('dynamicModule', {
// 模块定义
})
```
### 2. 表单处理方案
```javascript
// 使用双向绑定计算属性
computed: {
num: {
get() { return this.$store.state.count.num },
set(value) { this.$store.commit('count/UPDATE_NUM', value) }
}
}
```
### 3. 插件开发
```javascript
// 持久化插件示例
const persistPlugin = store => {
store.subscribe((mutation, state) => {
localStorage.setItem('vuex_state', JSON.stringify(state))
})
}
```
## 五、性能优化技巧
### 1. 大型状态树
- 使用模块懒加载
- 避免在state中存储大对象
### 2. 计算属性缓存
```javascript
getters: {
bigSum: state => {
// 复杂计算会被缓存
return heavyCalculation(state.sum)
}
}
```
### 3. 批量更新
```javascript
// 合并多个mutation
actions: {
bulkUpdate({ commit }, payload) {
commit('UPDATE_A', payload.a)
commit('UPDATE_B', payload.b)
}
}
```
## 六、常见问题解决方案
1. **热重载问题**
```javascript
if (module.hot) {
module.hot.accept(['./modules/count'], () => {
store.hotUpdate({ modules: { count } })
})
}
```
2. **循环依赖**
- 避免模块间互相引用
- 使用全局事件总线处理跨模块通信
3. **调试技巧**
- 使用Vue Devtools追踪状态变化
- 添加logger插件记录mutation
## 七、与Vue3的Pinia对比
| 特性 | Vuex | Pinia |
| ---------- | ------------ | -------- |
| 语法 | 较复杂 | 更简洁 |
| 模块化 | 需要配置 | 自动支持 |
| TypeScript | 需要额外配置 | 完美支持 |
| 体积 | 较大 | 更轻量 |

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<h1>当前求和为:{{ sum }}</h1> <h1>当前求和为:{{ $store.state.count.sum }}</h1>
<select v-model.number="num"> <select v-model.number="$store.state.count.num">
<option :value="1">1</option> <option :value="1">1</option>
<option :value="2">2</option> <option :value="2">2</option>
<option :value="3">3</option> <option :value="3">3</option>
@ -18,27 +18,20 @@
export default { export default {
name: "CountInfo", name: "CountInfo",
data() { data() {
return { return {};
num: 1,
sum: 0,
};
}, },
methods: { methods: {
increment() { increment() {
this.sum += this.num; this.$store.commit("count/INCREMENT");
}, },
decrement() { decrement() {
this.sum -= this.num; this.$store.commit("count/DECREMENT");
}, },
incrementOdd() { incrementOdd() {
if (this.sum % 2) { this.$store.dispatch("count/incrementOdd");
this.sum += this.num;
}
}, },
incrementWait() { incrementWait() {
setTimeout(() => { this.$store.dispatch("count/incrementWait");
this.sum += this.num;
}, 500);
}, },
}, },
}; };