Vuex状态管理(下)

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里的数据不能直接修改.

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/106866713