Vuex 模块化开发详解

Vuex 模块化开发详解

在实际项目中,当应用的状态管理变得复杂时,将 Vuex 的 store 拆分成多个模块是一个很好的实践。模块化开发可以帮助我们更好地组织代码,使每个模块专注于特定的功能,从而提高代码的可维护性和可读性。下面是 Vuex 模块化开发的详细介绍。

1. 未使用 mapXxxx 的模块化开发
1.1 模块文件创建

将不同功能的 store 逻辑拆分成多个 JavaScript 文件,例如 student.jsschool.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 提供的辅助函数(如 mapStatemapGettersmapActionsmapMutations)可以进一步简化组件中的代码,使数据和方法的调用更加简洁。

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 的模块化开发,使状态管理更加高效和易于维护。