Module
State,Action,Mutation,Getter学习较为简单,可以参考官网,Module较为复杂,所以记录,方便以后回顾。
由于使用单一状态,所有状态会集中一起。当应用变得非常复杂时,store 对象就会变得非常庞大且不好维护。所以为了解决这个问题,Module应运而生。
1.基本结构
可以将复杂的项目切成多个模块,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
const moduleA = {
state:{name:"moduleAName"}
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state:{name:"moduleBName"}
mutations: { ... },
actions: { ... }
}
const store = createStore({
state:{name:"rootName"}
modules: {
a: moduleA,
b: moduleB
}
})
2.各部分参数以及可以取到的值
(1)getters参数及其可取到的值
- state:获取modules中的state数据
- getters:获取modules中的getters数据
- rootState:获取根部state数据
- rootGetters:获取根部getters数据
(2)mutations参数及其可取到的值
- state:获取modules中的state数据
- 调用方法时传入的值
(3)mutations参数及其可取到的值
-
state:获取modules中的state数据
-
getters:获取modules中的getters数据
-
rootState:获取根部state数据
-
rootGetters:获取根部getters数据
-
commit:可以调用自身模块的mutations里面的方法,还可以加第三个参数
{root:true},这样可以调用根部mutations里面的方法。 -
dispatch:可以调用自身模块的actions里面的方法,还可以加第三个参数
{root:true},这样可以调用根部actions里面的方法。
3.命名空间
命名空间的产生是为了避免不同的模块使用相同名字的getter、mutation和action。使用namespaced: true来声明空间。使用命名空间对getter、mutation和action的调用产生影响。
const store = createStore({
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']
}
}
}
}
}
})
4.带命名空间的模块注册全局 action
在模块内部可以使用root: true注册全局命名空间的
my.vue
root.js
moduleA.js
5.带命名空间的绑定函数
为了方便使用定义好的模块内容,使用 mapState、mapGetters、mapActions 和 mapMutations,可以分别放在computed或者methods里面。
...mapState('moduleName',{
moduleAName:'stateName'
}),
...mapGetters('moduleName',{
getterName:'getterName'
})
...mapActions('moduleName', [
'moduleActionName',
])
...mapMutations('moduleName', [
'moduleMutationName',
]),
还可以通过使用 createNamespacedHelpers 这个辅助函数创建基于某个命名空间的内容
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('moduleName')
export default {
computed: {
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions([
'foo',
'bar'
])
}
}
6.模块动态注册
import { createStore } from 'vuex'
const store = createStore({})
// 注册模块 `myModuleName`
store.registerModule('myModuleName', {})
// 注册嵌套模块 `nested/myModuleName`
store.registerModule(['nested', 'myModuleName'], {})
可以使用 store.unregisterModule(moduleName) 来动态卸载模块。注意不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
可以通过 store.hasModule(moduleName) 方法检查该模块是否已经被注册到 store。需要记住的是,嵌套模块应该以数组形式传递给 registerModule 和 hasModule,而不是以路径字符串的形式传递给 module。
模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。
注册新模块的时候如何保留原来的State
action、mutation 和 getter 会被添加到 store 中。通过preserveState: true来保留原来的state。举例如下:
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
//使用preserveState: true
store.registerModule("c", moduleB, { preserveState: true });
//没有使用preserveState: true
store.registerModule("c", moduleB);
7.模块重用
当项目很大的时候,可能会有很多相似的模块,那么此时可以将公共的部分提取出来。但是如果不做处理直接使用的话,那么会产生变量污染。
//模块a和模块c都是用的moduleA
import moduleA from './moduleA/index'
const store = createStore({
state: {
rootName: 'this is the rootName'
},
modules: {
a: moduleA,
b: moduleB
},
mutations: {
changeRootName(state, paylaod) {
state.rootName = paylaod
},
},
actions: {
test({ commit, state, getters, dispatch, rootState, rootGetters }, payload) {
commit('edit', "This is a new root name ")
},
}
// plugins:[saveChangeName]
})
store.registerModule("c", moduleA);
通过vue-devtools查看结果
点击按钮之后结果如下,可以发现都变化了。
通过如下方式:可以隔绝掉相互之间的影响,从而回归正常。
const moduleA = {
namespaced: true,
state() {
return {
name: 'My moduleA name is moduleA'
}
}
}
export default moduleA