Vuex状态管理(下)
文章目录
一.引言
前面我们Vuex状态管理(上)我们了解了Vuex的五大核心概念的四个概念,State,Getters,Mutations,Actions,接下来我们讲讲最后一个与项目架构相关的一个核心概念:Module
二.背景
由于使用单一状态树,应有的所有的状态会集中到一个比较大的对象,当应用变得非常复杂时,store对象就有可能变得非常臃肿.
当我们的项目慢慢变得庞大时,数据关联的复杂性就更加大了,而Vue本就是数据驱动,vuex更是专门的数据状态仓库,更容易发生不可预知的关联性数据错误.
为了解决以上的问题,官方vuex允许我们将store分割成模块(module) .每个模块拥有自己的state.getter.mutation,action.甚至是嵌套子模块一一从上至下进行同样方式的分割.
项目越做越大,功能点越写越多,需要使用vuex共享的数据越来越庞大时,就需要使用module来进行仓库模块的分割了.
三.在Vuex中使用module
//拆分的仓库子模块A
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... },
//仓库子模块也可以继续做拆分,但是无必须要,反而更复杂
modules:{
aaaa,
bbbb,
}
}
//拆分的仓库子模块B
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
//仓库根模块
const store = new Vuex.Store({
//通过modules选项配置子模块
modules: {
//key:value形式
//key: a 仓库模块的名字
//value :moduleA 对应仓库子模块的对象
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
上面是官网中的示例代码,我做了点注解.助大家更容易理解模块的拆分
1.使用步骤
- 在src目录下新建store目录
- 在stroe目录下新建index.js和modules文件夹
- index.js是在Vuex实例中使用modules选项将合并module文件夹下的子模块合并
- modules文件夹下包含着各个拆分的功能模块的js文件,同样里面包含state,和getters,mutations,actions
index.js
//引入vue
import Vue from 'vue';
//引入vuex
import Vuex from 'vuex';
//注册
Vue.use(Vuex);
// 这就是一个store子模块
import A from './modules/a'
import B from './modules/b'
const store = new Vuex.Store({
// modules这个选项用于把子module进行合并
modules: {
A,
B
}
})
export default store
拆分后子模快.js
// 每一个子module实际上就是一个普通json对象,可以包括state、getters、mutations、actions这些选项
const studyModule = {
state: {
},
getters: {
},
mutations: {
},
actions: {
}
}
export default studyModule
后续无论你的功能有多大,只需要添加相应的js文件即可
2.拆分后遇到的问题
默认情况下,模块内部的state,mutations,getters,actions是注册在全局命名空间的
- 多个仓库子模块中的getter
- 多个仓库子模块中的mutation如果同名的话,组件调用这个mutation,都会被触发,会有被污染的危险
- 多个仓库子模块中的action,如果同名的话,组件调用这个action,都会被触发,会有被污染的危险
3.解决问题
1.设置命名空间
给子模块设置命名空间,在子模块的对象中,设置namespaced属性为true
2.调用设置命名空间后的子模块数据
//1.直接通过$store
this.$store.state.模块名.xxx
//2.computed
computed:{
aaa(){
return this.$store.state.模块名.xxx;
}
}
//3.mapState
computed:{
...mapState('xxxx',[state1,state2,state3])
}
//4.mapState的转换
computed:{
state1(){
retrurn this.$store.state.xxxx.state1;
}
}
注意:如果要在组件中同时拿到多个仓库中的子模块的同名state数据,不要使用mapState.
3.调用设置命名空间后的某仓库子模块中的getter
//1 直接通过$store
this.$store.getters['xxxx/想要的数据']
//2.computed
computed:{
aaa(){
return this.$store.getters['xxxx/想要的数据']
}
}
//3.mapGetters
computed:{
...mapGetters('xxxx',[getter1,getter2])
}
//4.mapGetters的转换
computed:{
getter1(){
return this.$store.getters['xxxx',getter1]
}
}
4.提交某个仓库子模块中的mutation
//1.直接通过$store
this.$store.commit('xxxx/某事件',payload)
//2.methods
methods:{
fn(payload){
this.$store.dispatch('xxxx/某事件',payload)
}
}
//3.mapActions
methods:{
...maActions('xxx',[action1,action2])
}
//4.mapActions的转换
methods:{
action1(payload){
this.$store.dispatch('xxxx/action1',payload)
}
}
四.仓库模块的局部状态
做了仓库模块的拆分后,getters与mutations中的第一个参数,是当前模块的局部state,action中的第一个参数context,context中的state也是当前模块的局部state
如果我们需要在getter中action中去获取到其余模块的state数据,
1.getter语法
getters:{
//state 当前模块的state
//getters 当前模块的getters
//rootState 根模块的state数据,根据它可以方便去拿其余模块的state
getter1(state,getters,rootState){
}
}
2.action语法
actions:{
//context 是个对象,这个对象中有些属性
// state 当前模块的局部state
// getters 当前模块的局部getters
// commit 提交mutation的方法
// dispatch 派发action的方法
// rootState 跟模块的state,可以获取其他模块的state
action1(context,payload){
}
}
注意:mutation没有rootState
如果需要在mutation中使用其余模块的state数据
可以使用payload,比如在action中获取到需要的rootState,然后作为mutation的payLoad传递过去
五.v-model绑定仓库中的数据情况
通过v-model绑定input框,v-model绑定仓库中的数据.当我们在input框中输入的时候,会报错,也没有引起仓库中数据变化
其实这个现象的根本原因,还是仓库中的state数据不允许直接修改,我们可以通过计算属性中的get() ,set()方法来解决这问题
- 1.仓库中需要提供一个mutation来处理变化
- 2.组件中给对应的computed提供一个getter,和setter
state:{
inputVal:"abc"
},
mutations:{
fn(state,payload){
state.inputVal=payload;
}
}
//组件上
computed:{
inputVal:{
get(){
return this.$store.state.inputVal;
}
//要修改依赖项提交mutations
set(value){
this.$store.commit('fn',value)
}
}
}
六. Vuex核心概念图解
Vuex的主要包含3个东西,State,Actions,Mutations,首先呢,我们来看看这图解的流程
Vuex里有个仓库,State,State里的数据可以直接拿到组件中做一个Render渲染,如果我们要改变State仓库里的东西,可以直接从组件派发dispatch一个Actions,Actions是不能直接修改State仓库的,只能提交Commit一个Mutation,然后在mutation中去修改State仓库里的数据.为什么只能用Mutations去修改呢,也是为了更好的与Devtools更好的集成,里面更好的利用Devtools的时间旅行机制.其实呢,我觉得还可以在Vue Components连一条线到Mutations上,因为可以直接在组件上commit一个Mutation,当然了,如果是异步的话,还是经过Actions,一般我们获取后台接口数据的话,还是在Actions里进行的.同步的话还是使用Mutations.
注意:仓库中的state数据,不允许直接修改,只是一个规定,真正使用的话,是不会报错的.但是不推荐.为了更好的的处理报错情况,所以state数据都是映射到组件的computed上.因为computed里的数据不能直接修改.