六、Vuex - Module
Module 模块
Vuex 允许将 store 分割成模块(module), 每个模块拥有自己的state、mutation、action、getter甚至是嵌套子模块, 从上至下进行同样方式的分割。分割的好处是让代码更加清晰, 易于维护管理.
模块划分及访问
// A 模块
const moduleA = {
state: {},
getters: {},
mutations: {},
actions: {}
}
// B 模块
const moduleB = {
state: {},
getters: {},
mutations: {},
actions: {}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
});
// 访问独立模块的状态
store.state.a // 访问 moduleA 的状态
store.state.b // 访问 moduleB 的状态
模块的局部状态
- 模块内部的 mutation、getter 的第一个参数为模块的局部状态对象
- 模块内部的 action中, 局部状态通过 context.state 暴露, 根节点点状则为 content.rootState
- 模块内部的 getter, 根节点的状态会作为第三个参数暴露出来
const moduleA = {
getters: {
getCount (state, getters, rootState) {
// state 局部状态
// 局部 getters,
// rootState 根节点状态
return state.count + rootState.count;
}
},
mutations: {
increment (state) {
state.count++;
// state 模块的局部状态
}
},
actions: {
increment ({ state, commit, rootState }) {
// state 局部状态
// rootState 根节点状态
commit('increment');
}
}
}
命名空间
默认情况下, 模块内部的 action、mutation、getter 是注册在全局命名空间的, 这样使得多个模块能够对同一mutation或action作出响应
如果希望你的模块具有更高的封装和复用性, 你可以通过天剑 namespaced: true 的方式使其成为带命名空间的模块。
当模块被注册后, 所有 getter、action及mutation 都会自动根据模块注册的路径调整命名。
const store = new Vuex.Store({
modules: {
account: {
namespaced: true,
// 模块内容
sstate: {},
getters: {
inAdmin () {} // getters['account/isAdmin']
},
mutations: {
login () {} // commit('account/login')
},
actions: {
login () {} // dispatch('account/login')
},
// 嵌套模块
modules: {
// 继承父模块的命名空间
myPage: {
state: {},
getters: {
profile () {} // getter['account/profile']
}
},
// 进一步嵌套命名空间
posts: {
namespaced: true,
state: {},
getters: {
popular () {} // getter['account/posts/popular']
}
}
}
}
}
});
在带命名空间的模块内访问全局内容
- 使用全局的 state 和 getter, rootState 和 rootGetters 会作为第三和第四参数传入 getter, 也会通过 context 对象的属性传入action
- 分发和提交全局命名空间的action、mutation, 将 { root: true } 作为第三参数传给 dispatch 或 commit 即可
modules: {
foo: {
namespaed: true,
getters: {
someGetter (state, getters, rootState, rootGetters) {
getters.someOther // 'foo/someOther'
rootGetters.someOhter // 'someOther'
}
},
actions: {
someAction ({ dispatch, commit, getters, rootGetters }) {
dispatch('someOtherAction') // 'foo/someOhterAction'
dispatch('someOtherAction', null, { root: true }) // 'someOhterAction' 派发根节点的 action
commit('someMutation') // 'foo/someMutation'
commit('someMutation', null, { root: true }) // 'someMutation' 提交根节点的 mutation
}
}
}
}
在命名空间模块中注册全局 action
action: {
someAction: {
root: true, // 将注册到全局中
handler () {}
}
}
带命名空间的模块如何使用
当使用 mapState、mapGetters、mapActions、mapMutations时需要注意
// 方式一: 统一编写
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
methods: {
...mapActions([
// this['some/nested/module/foo']()
'some/nested/module/foo',
'some/nested/module/bar'
])
}
// 方式二: 将模块的空间名称作为第一个参数,自动绑定模块上下文
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', {
'foo', // this.foo()
'bar' // this.bar()
})
}
// 方式三: 通过 createNamespacedHelpers 创建基于某个命名空间辅助函数
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapAction } = createNamespacedHelpers('some/nested/module');
export default {
computed: {
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions([
'foo',
'bar'
])
}
}