前言
今日早读文章由腾讯@红烧牛肉面投稿分享。
正文从这开始~~
模块(Module)是什么
Vuex在简单应用中的使用相信大家都会,但是当应用变得复杂时,store对象就可能变得臃肿,这时可以使用module解决这个问题。
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }}const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }}const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB}})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
模块(Module)动态注册
在前面的官方示例代码中,moduleA和moduleB都是预先知道的,那如果module无法预知呢?
需求:提供一个具有基础功能的版本,其他团队在此基础版上添加团队的定制功能
在这种需求下,Vuex的module设计采用动态注册(store.registerModule)是比较合适的。
// store.jsexport default new Vuex.Store({})// components/base.vue 基础功能组件import '../modules/base'export default {...};script>// modules/base.js 基础功能moduleimport baseStore from '../store'let store = {
state: {},
mutations: {},
actions: {
init() {
console.log('baseModule:init')}},
getters: {}}
baseStore.registerModule('base', store)// components/team1.vue 团队1定制功能组件import '../modules/team1'export default {...};script>// modules/team1.js 团队1定制功能moduleimport baseStore from '../store'let store = {
state: {},
mutations: {},
actions: {
init() {
console.log('team1Module:init')}},
getters: {}}
baseStore.registerModule('team1', store)// 类似还有 team2和team3...
补充知识点一:卸载模块
你也可以使用 store.unregisterModule(moduleName) 来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
补充知识点二:保留state
在注册一个新 module 时,你很有可能想保留过去的 state,例如从一个服务端渲染的应用保留 state。你可以通过 preserveState 选项将其归档:store.registerModule(‘a’, module, { preserveState: true })。
当你设置 preserveState: true 时,该模块会被注册,action、mutation 和 getter 会被添加到 store 中,但是 state 不会。这里假设 store 的 state 已经包含了这个 module 的 state 并且你不希望将其覆写。
模块(Module)命名空间
问题:当基础功能和团队定制功能包含相同名称的action、mutation 和 getter时,会同时被触发
// components/base.vuethis.$store.dispatch('init')//输出
baseModule:init
team1Module:init
team2Module:init
team3Module:init
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
把store打印出来,对上面这句话会有更直观的感受
![0fcac4aa3a730fab9e4726f74e7d98d3.png](https://img-blog.csdnimg.cn/img_convert/0fcac4aa3a730fab9e4726f74e7d98d3.png)
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
// components/base.vue// !!!注意:有命名空间时action名称需要加上registerModule时注册的模块名this.$store.dispatch('base/init')// modules/base.js 基础功能moduleimport baseStore from '../store'let store = {
namespaced: true,...}// 有命名空间时dispatch时需要带上这里传入的'base'前缀
baseStore.registerModule('base', store)// modules/team1.js 团队1定制功能moduleimport baseStore from '../store'let store = {
namespaced: true,...}// 同样,有命名空间时,dispatch时需要带上这里传入的'team1'前缀
baseStore.registerModule('team1', store)
// components/base.vuethis.$store.dispatch('base/init')//输出
baseModule:init
再来看下store的打印
![43e3e8f9138cb0285426c48f8a0c243b.png](https://img-blog.csdnimg.cn/img_convert/43e3e8f9138cb0285426c48f8a0c243b.png)
模块(module)访问全局命名空间
需求:基础功能和定制功能需要获取权限信息进行管理
获取权限是个通用的功能,放在全局命名空间是比较合适的
//store.jsexport default new Vuex.Store({
actions:{
getPermission() {
console.log('request permission')}}})
若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。
// modules/base.js 基础功能moduleimport baseStore from '../store'let store = {...
actions: {
init({dispatch}) {
console.log('baseModule:init')
dispatch('getPermission',null,{root:true})}}}// modules/team1.js 团队1定制功能moduleimport baseStore from '../store'let store = {...
actions: {
init({dispatch}) {
console.log('team1Module:init')
dispatch('getPermission',null,{root:true})}}}
store的插件机制
需求:对所有模块的dispatch接口调用进行数据统计
可以通过store的插件机制暴露出每个action的钩子。
//store.jsconst myPlugin = store => {
store.subscribeAction((action, state) => {
console.log( 'report:', action.type)})}export default new Vuex.Store({
plugins: [myPlugin],...})
补充知识点:subscribeAction 是在2.5.0新增的。mutation也是可以通过 subscribe 订阅的。
参考资料
Vuex Module
Vuex API参考
关于本文
作者:@红烧牛肉面
原文:https://github.com/masterkong/blog/issues/11
他曾分享过
【第1291期】Puppeteer入门简介
为你推荐
【第1586期】基于Redux/Vuex/MobX等库的通用化状态OOP
【第1525期】Vuex、Flux、Redux、Redux-saga、Dva、MobX