Vuex模块化使用 与 namespaced命名空间

4,530 阅读3分钟

这两天整理项目时发现自己对Vuex模块化的使用还不够熟悉,虽然namespaced: true已经刻在DNA里了,但是读取仓库数据时mapStatemapActions等辅助函数写得不算很顺畅,所以来复习一下,把整个模块化的流程都自己梳理总结一遍,下一次就可以更加优雅流利地敲代码了。Above all, 开启命名空间并且使用辅助函数会更加方便噢。

首先指路官方文档,更加详细深入的教程。

下面是我的总结:

为什么要模块化

  • Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT (opens new window))”而存在。这也意味着,每个应用将仅仅包含一个 store 实例

  • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿

  • 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)

模块 module

每个模块都可配置自己的 statemutationsactionsgetters、甚至是嵌套子模块modules。 但是注意,最终所有独立的模块都是在一个store对象里面。

export default {
    namespaced: true,
    actions:{
        // 奇数再加
        oddAdd(context, value) {
            // 判断是否为奇数
            if (!context.state.sum % 2) {
                context.commit('ODDADD', value)
            }
        },

        // 等一会儿先
        waitAdd(context, value) {
            setTimeout(() => {
                context.commit('WAITADD', value)
            }, 500)
        }
    },
    mutations:{
        ADD(state, value) {
            // console.log('mutations被调用了',state,value);
            state.sum += value
        },
        SUBTRACT(state, value) {
            state.sum -= value
        },
        ODDADD(state, value) {
            state.sum += value
        },
        WAITADD(state, value) {
            state.sum += value
        },
    },
    state:{
        sum: 0,
        school: '北京大学',
        study: '经济学',
        student: 'Lindsay',
    },
    getters:{
        bigSum(state) {
            return state.sum * 10   //return决定值
        }
    }
}

注:以下所有示例代码都基于上面贴出的countOPTIONS模块

模块化使用

  1. 在store文件夹下新建modules文件夹,里面存放所有独立的模块

image.png

  1. 在index.js中引入各个模块,添加modules配置项并向外暴露
// 引入Vue 构造函数
import Vue from 'vue'
// 引入Vuex插件
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)

import countOPTIONS from './countOPTIONS'
import personOPTIONS from './personOPTIONS'

//  生成store实例的方法--- new Vuex({配置项})
//  创建store实例,同时默认暴露
export default new Vuex.Store({
    modules: {
        countOPTIONS, personOPTIONS
    }
})

namespaced命名空间

开启方式: 在独立的模块中添加配置项 namespaced: true

  • 带命名空间的模块,具有更高的封装度和复用性
  • 当模块被注册后,它的所有 getteractionmutation 都会自动根据模块注册的路径调整命名。

直接-获取数据

state

语法:$store.state.模块名.state属性名

    $store.state.countOPTIONS.sum

getters

语法:$store.getters['模块名/getter属性名']

    $store.getters.['countOPTIONS/bigSum']

commit && dispatch

语法:$store.commit('模块名/mutation名') && $store.dispatch('模块名/action名')

    $store.commit('countOPTIONS/ADD')    $store.dispatch('countOPTIONS/Add')

当获取数据的需求比较大时,通常采用辅助函数

辅助函数-获取数据

// 当然大前提是需要先引入辅助函数
import {mapState,mapActions,mapGetters,mapMutations} from 'vuex'

mapState

写在computed计算属性中,将模块的空间名称字符串作为第一个参数

// 第二个参数

// 1. 写成数组形式(生成的计算属性和state中的数据拥有一样的名称,双引号不能省略)
...mapState('countOPTIONS',["sum", "student", "school", "study"])


// 2. 写成对象形式 
...mapState('countOPTIONS',{
      sum: state => state.sum,
      student: state => state.student,
      school: state => state.school,
      study: state => state.study,
    }
    

// 自命名生成的计算属性
//...mapState('countOPTIONS',{a:'sum', b:'student', b:'school', d:'study'})
    

我更喜欢第一种写法,数组的形式写起来简便很多。

下面的3个辅助函数都采取了数组写法,对象写法省略。

mapGetters

// 数组形式 (生成的计算属性和state中的数据拥有一样的名称,双引号不能省略)
...mapGetters('countOPTIONS',["bigSum"])

mapActions && mapMutations

...mapActions('countOPTIONS',["Add", "Subtract"])

...mapMutations('countOPTIONS',["ADD", "SUBTRACT"])