Vuex 模块化开发详解
在实际项目中,当应用的状态管理变得复杂时,将 Vuex 的 store 拆分成多个模块是一个很好的实践。模块化开发可以帮助我们更好地组织代码,使每个模块专注于特定的功能,从而提高代码的可维护性和可读性。下面是 Vuex 模块化开发的详细介绍。
1. 未使用 mapXxxx 的模块化开发
1.1 模块文件创建
将不同功能的 store 逻辑拆分成多个 JavaScript 文件,例如 student.js
和 school.js
,每个文件负责管理特定模块的状态、动作、突变和获取器。
student.js
// student 模块
export default {
// 开启命名空间
namespaced: true,
actions: {
// 学生 actions
stuNumFun(context) {
context.commit("STU_NUM_FUN");
},
},
mutations: {
// 学生 mutations
STU_NUM_FUN(state) {
state.studentNum += 2;
},
STU_NAME_FUN(state) {
state.studentName += "!";
},
},
getters: {
// 学生名反转
reverseStudentName(state) {
return state.studentName.split("").reverse().join("");
},
},
state: {
// 学生数据
studentNum: 5,
studentName: "章三",
},
};
school.js
// school 模块
export default {
// 开启命名空间
namespaced: true,
actions: {
// 学校 actions
schNumFun(context) {
context.commit("SCH_NUM_FUN");
},
},
mutations: {
// 学校 mutations
SCH_NUM_FUN(state) {
state.schoolNum += 1;
},
SCH_NAME_FUN(state) {
state.schoolName += "@";
},
},
getters: {
// 学校名反转
reverseSchoolName(state) {
return state.schoolName.split("").reverse().join("");
},
},
state: {
// 学校数据
schoolNum: 66,
schoolName: "北京大学",
},
};
1.2 引入模块到 store.js
在主 store 文件中引入这些模块,并将它们注册到 Vuex 的 store 中。
store.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// 导入各vuex模块
import student from "./student";
import school from "./school";
export default new Vuex.Store({
modules: {
student,
school,
},
});
1.3 组件中使用模块化数据
在组件中访问模块化的 state 和 getters 时,需要通过模块名进行访问。
student.vue
<template>
<div>
<h1>student</h1>
<h2>studentNum:{
{ $store.state.student.studentNum }}</h2>
<h3>reverseStudentName:{
{ $store.getters['student/reverseStudentName'] }}</h3>
<button @click="stuNumFun">stuNum++</button>
<button @click="stuNameFun">stuName+@</button>
</div>
</template>
<script>
export default {
name: 'student',
methods: {
stuNumFun() {
this.$store.dispatch('student/stuNumFun')
},
stuNameFun() {
this.$store.commit('student/STU_NAME_FUN')
}
}
}
</script>
school.vue
<template>
<div>
<h1>school</h1>
<h2>schoolNum:{
{ $store.state.school.schoolNum }}</h2>
<h2>reverseSchoolName:{
{ $store.getters['school/reverseSchoolName'] }}</h2>
<button @click="schNumFun">schNum++</button>
<button @click="schNameFun">schName+@</button>
</div>
</template>
<script>
export default {
name: 'school',
methods: {
schNumFun() {
this.$store.dispatch('school/schNumFun')
},
schNameFun() {
this.$store.commit('school/SCH_NAME_FUN')
}
}
}
</script>
2. 使用 mapXxxx 的模块化开发
使用 Vuex 提供的辅助函数(如 mapState
、mapGetters
、mapActions
、mapMutations
)可以进一步简化组件中的代码,使数据和方法的调用更加简洁。
2.1 引入辅助函数
在组件中引入这些辅助函数,并在计算属性和方法中使用它们。
student.vue
<template>
<div>
<h1>student</h1>
<h2>studentNum:{
{ studentNum }}</h2>
<h3>reverseStudentName:{
{ reverseStudentName }}</h3>
<button @click="stuNumFun">stuNum++</button>
<button @click="stuNameFun">stuName+@</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
name: 'student',
computed: {
// map模块化获取数据
...mapState('student', ['studentNum']),
...mapGetters('student', ['reverseStudentName'])
},
methods: {
// 对象形式
...mapActions('student', { stuNumFun: 'stuNumFun' }),
...mapMutations('student', { stuNameFun: 'STU_NAME_FUN' })
}
}
</script>
school.vue
<template>
<div>
<h1>school</h1>
<h2>schoolNum:{
{ schoolNum }}</h2>
<h2>reverseSchoolName:{
{ reverseSchoolName }}</h2>
<button @click="schNumFun">schNum++</button>
<button @click="SCH_NAME_FUN">schName+@</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
name: 'school',
computed: {
...mapState('school', ['schoolNum']),
...mapGetters('school', ['reverseSchoolName'])
},
methods: {
// 数组形式
...mapActions('school', ['schNumFun']),
...mapMutations('school', ['SCH_NAME_FUN'])
}
}
</script>
3. 模块中发送 AJAX 请求
在模块化的 action 中,可以发送 AJAX 请求以获取数据,并通过 commit 提交 mutations 来更新 state。
test.js
import axios from "axios";
export default {
namespaced: true,
actions: {
// 请求数据
async getUserInfo(context) {
try {
let res = await axios.get("api/user");
context.commit("GET_USER_INFO", res.data);
} catch (error) {
console.log(error.message);
}
},
},
getters: {
},
mutations: {
// 更新state数据
GET_USER_INFO(state, value) {
state.list = value;
},
},
state: {
list: [],
},
};
test.vue
<template>
<div>
<h2>test</h2>
<button @click="getUserInfo">发送数据,并展示</button>
<ul>
<li v-for="(item, index) in list" :key="index">{
{ item.name }}</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
name: 'test',
methods: {
...mapActions('test', ['getUserInfo'])
},
computed: {
...mapState('test', ['list'])
}
}
</script>
4. 模块化开发的注意事项
- 命名空间:在模块中开启
namespaced: true
,这样在访问模块中的数据和方法时需要通过模块名进行限定,避免命名冲突。 - 模块拆分:根据功能或业务逻辑将 store 拆分成多个模块,每个模块管理自己的 state、mutations、actions 和 getters。
- 代码复用:通过模块化开发,可以提高代码的复用性,便于在不同的项目或组件中共享代码。
- 维护性:模块化使得代码结构更加清晰,便于后期的维护和扩展,每个模块可以独立开发和测试。
通过以上步骤和注意事项,可以实现 Vuex 的模块化开发,使状态管理更加高效和易于维护。