Vuex 模块化使用详解
前言上回我们说了一下vuex的简单使用,最后面的时候有说了,由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
为了解决以上问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割,今天我们也来简单了解一下他的使用,深入学习可能还是要去看官方文档
1文件结构
文件结构的话,模块化的使用要多一个modules的文件夹,里面放着细分模块的js文件/模块名文件夹。
这里官方的标准是一个模块一个js文件,但是要是模块太复杂的话,也可以把里面的代码拆分出来。
//store文件夹 │actions.js │getters.js │index.js │mutations.js │state.js │ └─modules │moduleB.js │ └─moduleA index.js mutation.js state.js
然后在创建store的js文件中引入这些模块,直接
importmoduleAfrom'./modules/moduleA/index' importmoduleBfrom'./modules/moduleB'; exportdefaultnewVuex.Store({ state, getters, mutations, actions, modules:{ moduleA, moduleB, } });
2模块的局部状态对象的定义
模块内部的getter,mutation和action,他们方法接收的参数会和根状态的不一样,我们一个一个来
getter
getter的话,他会有三个参数,第一个是模块内的state,第二个是模块内的getters,第三个是根节点状态rootState,
constgetters={ bFullName:(state,getters,rootState)=>`full${state.bName}` }
mutation
mutation里面的回调函数传入的第一个参数也是模块内的state,其他和根状态定义的时候一样
constmutations={ //这里的`state`对象是模块的局部状态 SET_B_NAME(state,payload){ debugger state.bName=payload.name; } }
action
最后的action的话,他传入还是只有context对象,然后咧,这个对象里面的state属性指模块内的状态,rootState指根状态,如下
constactions={ ASYNC_SET_NAME({state,commit,rootState},payload){ setTimeout(()=>{ state.bName='asyncName' },4000) } }
3使用
3.1state获取
这个的话要在原来状态名前面加一个模块名才能放到到模块内的对象。具体如下
//原先的基础上加个模块名 this.$store.state.moduleB.bName; //辅助函数也一样,name前面加个模块名Deno ...mapState({ name:state=>state.moduleB.bName, })
3.2命名空间
getter,mutation,action他们默认都是注册在全局命名空间的,所以我们默认是可以和使用根状态一样去使用他们,但是这样不可避免会出现命名冲突的问题,所以使模块有更高的封装性与复用性,我们可以通过添加`
namespaced:true`使其成为带命名空间的模块。当模块被注册后,它的所有getter、action及mutation都会自动根据模块注册的路径调整命名。
//moduleB模块导出的时候加个namespaced:true, exportdefault{ namespaced:true, state, getters, mutations, actions, }
3.2.1辅助函数的使用
因为有了命名空间这么一层封装,所以我们在用辅助函数的时候都要多加那么一层模块名,具体看下面代码。
//getter this.$store.getters['moduleB/bFullName']; ...mapGetters({ bGetter2:'moduleB/bFullName' }) //mutation this.$store.commit('moduleB/SET_B_NAME',{ name:'QQ' }); ...mapMutations({ setBname:'moduleB/SET_B_NAME' }), //action this.$store.dispatch('moduleB/ASYNC_SET_NAME',{name:"JJ"}); ...mapActions({ aSetAge:'moduleB/ASYNC_SET_NAME', }),
每次都要写模块名,这样写下来很烦,所以这些辅助函数给我们提供了一个参数位来绑定命名空间。
//moduleB模块内的bName ...mapState('moduleB',{ name:state=>state.bName }) //同理mapActionmapMutation也可以这个样子 ...mapAction('moduleB',[ '/ASYNC_SET_NAME' ])
除了这个之外,如果你当前组件用的vuex状态都是一个模块的话,我们可以使用createNamespacedHelpers创建基于某个命名空间辅助函数,如下:
import{createNamespacedHelpers}from'vuex' const{mapState,mapActions}=createNamespacedHelpers('moduleB')//moduleName
这样创建之后,我们就可以用之前的写法来访问到模块的状态。
...mapState({ bName:state=>state.bName, }),
3.2.2在带命名空间的模块内访问全局内容
如果你希望使用全局state和getter,rootState和rootGetter会作为第三和第四参数传入getter,也会通过context对象的属性传入action。
若需要在全局命名空间内分发action或提交mutation,将{root:true}作为第三参数传给dispatch或commit即可。具体看下面代码:
modules:{ foo:{ namespaced:true, getters:{ //在这个模块的getter中,`getters`被局部化了 //你可以使用getter的第四个参数来调用`rootGetters` someGetter(state,getters,rootState,rootGetters){ getters.someOtherGetter//->'foo/someOtherGetter模块内的getter' rootGetters.someOtherGetter//->'someOtherGetter全局的getter' }, someOtherGetter:state=>{...} }, actions:{ //在这个模块中,dispatch和commit也被局部化了 //他们可以接受`root`属性以访问根dispatch或commit someAction({dispatch,commit,getters,rootGetters}){ getters.someGetter//->'foo/someGetter' rootGetters.someGetter//->'someGetter' dispatch('someOtherAction')//->'foo/someOtherAction'模块内的action dispatch('someOtherAction',null,{root:true})//->'someOtherAction'全局的action commit('someMutation')//->'foo/someMutation'模块内的action commit('someMutation',null,{root:true})//->'someMutation'全局mutation }, someOtherAction(ctx,payload){...} } } }
3.2.3将模块内的action注册为全局
这个感觉和维护模块的封装性有点冲突,但是既然作者提出来了,那就学吧,当我们想要我们模块内的某个action提升为全局action的时候,在他声明的时候,添加root:true,并将action的定义放到hanler函数中,具体如下:
constactions={ //模块内action [ASET_AGE]({commit},payload){ setTimeout(()=>{ commit('SET_B_NAME',payload.name); },2000) }, //提升到全局的action globalAction:{ root:true, handler({commit},payload){ debugger setTimeout(()=>{ commit('SET_B_NAME',payload.name); },2000) } } }
关于模块使用Vuex的介绍就说到这里了,这两篇笔记的项目源码我发到了GitHub上面,大家可以去看一下,要是项目中有啥不明白的或者我说的有问题的,欢迎大家留言指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。