Vuex 核心概念之 Module && 命名空间

72 阅读2分钟

Vuex 核心概念之 Module

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

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

// moduleA.js
export const moduleA = {
  state: {
    a: 1
  },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

// moduleB.js
export const moduleA = {
  state: {
    b: 1
  },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

// store/index.js
import {moduleA} from './moduleA.js'
import {moduleB} from './moduleB.js'

export default new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

// 组件中获取state
this.$store.state.a   // -> moduleA 的状态
this.$store.state.b   // -> moduleB 的状态

命名空间

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

// moduleA.js
export const moduleA = {
  namespaced: true,
  state: {
    loginInfo: 'admin'
  },
  mutations: {
    login() {...}   // commit('a/login')
  },  
  actions: {
    login() {...}   // dispatch('a/login')
  },
  getters: {
    isAdmin() { ... }  // getters['a/isAdmin']
  }
}


// store/index.js
import {moduleA} from './moduleA.js'
import {moduleB} from './moduleB.js'

export default new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

也可以写成

export const moduleA = {
  account: {
    namespaced: true,
    state: {
      loginInfo: 'admin'
    },
    mutations: {
      login() {...}   // commit('account/login')
    },  
    actions: {
      login() {...}   // dispatch('account/login')
    },
    getters: {
      isAdmin() { ... }  // getters['account/isAdmin']
    }
  }
}

启用了命名空间的 getter 和 action 会收到局部化的 getterdispatch 和 commit。换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。更改 namespaced 属性后不需要修改模块内的代码。

带命名空间的绑定函数

当使用 mapStatemapGettersmapActions 和 mapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:

computed:{
  // 借助mapState生成计算属性,从state中读取数据(数组写法)
  ...mapState('a',['a']),
  ...mapGetters('a',['xxx'])
  
  methods: {
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象的写法)
    ...mapMutations('a',{increment: 'xxx', decrement: 'xxx'}),

    // 借助mapActions生成对应的方法,方法中会调用commit去联系mutations(对象的写法)
    ...mapActions('a',{incrementOdd:'xxx', incrementWait:'xxx'}),
  },
},