modules提出的目的:
“由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。”
模块化思想在做项目较大的时候十分有用,下面依据vuex文档简单记录一下modules的使用方式
如何使用modules
const moduleA = { state: { ... },//局部state mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... },//局部state mutations: { ... }, actions: { ... } } const store = new Vuex.Store({
state:{ ... },//全局state modules: { a: moduleA, b: moduleB } })
1.其中moduleA和modulesB的state为局部state,而store对象建立时与modules同级的为全局state
访问moduleA中的state :store.state.a, 全局state :store.state
2.对于moduleA和moduleB的getters和mutations中,对于参数与全局的getters和mutations存在一定区别
getters和mutations中第一个参数的state为局部state,
getters的第二个参数为全局getters,第三个为根state(rootState)
3.对于moduleA和moduleB的和mutations中
局部state通过context.state,全局state通过content.rootState ,全局getters通过rootGetters
actions: { test({ state, rootState }) { .... }
4.moduleA和moduleB除了state为局部,其他stategetters和mutations,actions可以全局直接使用,但参数的作用域全局的存在不同
module 的命名空间
什么是命名空间,就是在module中添加一个属性,namespaced: true,
就完成了,而命的名字就是在全局中导入的module的名字,
如上边代码中moduleA对应的a为其名字。
- 注意:module中state不受命名空间影响,本身就是局部state的
- 而getters和mutations,actions在命名后为局部,不能直接在全局调用
代码来自vuex文档
const store = new Vuex.Store({ modules: { account: { namespaced: true, // 模块内容(module assets) state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响 getters: { isAdmin () { ... } // -> 调用需要添加指定命名,getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login') }, // 嵌套模块 modules: { // 继承父模块的命名空间 myPage: { state: { ... }, getters: { profile () { ... } // -> getters['account/profile'] } }, // 进一步嵌套命名空间 posts: { namespaced: true, state: { ... }, getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } } })
在命名空间里面你要是想访问全局的getters,mutations和actions的话,需要注意一些
getters存在四个参数,state(局部), getters(局部), rootState(全局), rootGetters(全局)
例子
getters: { // 在这个模块的 getter 中,`getters` 被局部化了 // 你可以使用 getter 的第四个参数来调用 `rootGetters` someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter' rootGetters.someOtherGetter // -> 'someOtherGetter' }, someOtherGetter: state => { ... } },
对于mutation,不存在rootState可以访问全局state
对于action,存在rootState和rootGetters
接下来一个问题,因为命名空间,commit和dispatch都局部化,所以如何使用全局的commit和dispatch呢
答案是:通过传入{root:true}作为第三个参数打开路径调用全局的commit和dispatch
直接上例子
actions: { // 在这个模块中, dispatch 和 commit 也被局部化了 // 他们可以接受 `root` 属性以访问根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) { dispatch('someOtherAction') // -> 'foo/someOtherAction' dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction' commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' },
如果你想在module中注册一个全局的actions,可以通过如下方式,
在actions中添加一个属性(action函数名字),通过对象方式,添加root为true的属性以及在handle中添加action方法{root:true,handle(){...}}
actions: { someAction: { root: true, handler (namespacedContext, payload) { ... } // -> 'someAction' } }
接下来是如何将命名空间与语法糖(mapState,mapMutations,mapGetters,mapActions)结合起来
...mapState({ a: state => state.moduleA.a, b: state => state.moduleB.b })
...mapGeters({
a:"moduleA/a"
})
...mapActions([‘moduleA/foo
’]) =>使用为 this[moduleA/foo
]()
...mapMutations([‘moduleA/foo
’])=>使用为 this[moduleA/foo
]()
如上所见,简单直白
关于上边为什么mapState和mapGetters为什么要采用这种方式,起一个别名a,由于不起别名a,如何采用同Action和Mutation一样的写法的话
emm,那么使用为this['moduleA/a'],但是在template使用模板语法的时候表示为{{this['moduleA/a']}}得不出想要的数据,所以采用别名
获取另一种写法
...mapState(“moduleA”,["a"])
...mapGetters("moduleA",["a"] ...mapActions("moduleA",[‘foo’]) =>使用为 this.foo() ...mapMutations("moduleA",[‘foo’]) =>使用为 this.foo()
如果你觉得需要些指定命名的路径比较麻烦,你可以调用createNamespacedHelpers
这个创建某个命名空间的辅助函数
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('moduleA')
...mapState({ a: state => state.a, b: state => state.b }) ...mapActions([‘foo’]) =>使用为 this.foo() ...mapMutations([‘foo’]) =>使用为 this.foo()