vuex 多模块时 模块内部的mutation和action的调用方式


Posted in Javascript onJuly 24, 2020

vue在做大型项目时,会用到多状态管理,vuex允许我们将store分割成多个模块,每个模块内都有自己的state、mutation、action、getter。模块内还可以继续嵌套相对应的子模块。

为了巩固我自己对store多模块的一些基本认识,写了个简单的多模块实例,下图为我自己创建的store的目录结构,modules文件夹内的模块,在实际项目中还可以继续分开类似store目录下的多文件结构,也就是单独的模块文件夹,方便后期修改。

vuex 多模块时 模块内部的mutation和action的调用方式

store目录结构

./store/index.js的代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
// import mutations from './mutations'
import modulesA from './modules/modulesA'
import modulesB from './modules/modulesB'
 
Vue.use(Vuex)
 
const state = {
 logined: false,
 userid: -1
}
 
const store = new Vuex.Store({
 state,
 mutations: {
  'UPDATE_LOGIN_STATUS': (state, payload) => {
   state.logined = true
  }
 },
 modules: {
  modulesA: modulesA,
  modulesB: modulesB
 }
})
 
export default store

这里为了方便和子模块进行对比,我将mutations.js的代码放到index.js里面

modulesA.js的代码如下:

const moduleA = {
 namespaced: true,
 state: {
  isVip1: false
 },
 mutations: {
  'UPDATE_TO_VIP1': (state, payload) => {
   state.isVip1 = true
  }
 },
 actions: {
  getVip1 ({ state, commit, rootState }) {
   commit('UPDATE_TO_VIP1')
  }
 },
 getters: {}
}
export default moduleA

modulesB.js的代码如下:

const moduleB = {
 // namespaced: true,
 state: {
  isVip2: false
 },
 mutations: {
  'UPDATE_TO_VIP2': (state, payload) => {
   state.isVip2 = true
  }
 },
 actions: {
  getVip2 ({ state, commit, rootState }) {
   commit('UPDATE_TO_VIP2')
  }
 },
 getters: {}
}
export default moduleB

估计看到这里,你会发现modulesA和modulesB的区别就是有无namespaced这个属性。在vuex内,模块内部的action、mutation、getter都会被注册在全局命名空间内,俗话就是注册成全局的,这样做的结果就是在调用相对应的名字的的action或者mutation或者getter的时候,所有同名的都将会被响应。让我们来看看当没有namespaced(或者值为false)的时候,在组件内是怎么调用的,代码如下:

<template>
 <div class="hello">
  <h1>{{ msg }}</h1>
  <ul>
   <li>global state <strong>logined</strong>: {{ globalState }}</li>
   <li>modulesA state <strong>isVip1</strong> {{ modulesAState }}</li>
  </ul>
 </div>
</template>
 
<script>
export default {
 name: 'test',
 data () {
  return {
   msg: 'Test vuex mutilple modules'
  }
 },
 created () {
  console.log(this.$store.state)
  setTimeout(() => {
   this.$store.commit('UPDATE_LOGIN_STATUS')
  }, 1000)
  setTimeout(() => {
   this.$store.commit('UPDATE_TO_VIP1')
   // this.$store.dispatch('getVip1')
  }, 2000)
  setTimeout(() => {
   // this.$store.commit('CANCEL_VIP1')
   this.$store.dispatch('cancelVip1')
  }, 3000)
 },
 computed: {
  globalState () {
   return this.$store.state.logined
  },
  modulesAState () {
   return this.$store.state.modulesA.isVip1
  }
 }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

执行代码的截图如下:

vuex 多模块时 模块内部的mutation和action的调用方式

可以看到,我在store里面commit一个UPDATE_LOGIN_STATUS,将最顶层state中的logined的值改为true。2s的时候在store里面commit了UPDATE_TO_VIP1和3s的时候dispatch了一个事件CANCEL_VIP1,将modulesA的isVip1的值从false => true => false。说明没有开启命名空间是可以直接commit或者dispatch子模块内相对应的方法名,是可以修改到自身state中的属性的。

如果namespaced的值为true时,那么就是开启了命名空间模块,调用子模块的getter、mutation、getter的时候就跟之前不一样了,vuex它内部会自动根据模块注册的路径调整命名,比如要dispatch B中的一个action的话,那么组件内的调用就应该是如下这样的:

// this.$store.dispatch('modulesB/getVip2')

this.$store.commit('modulesB/UPDATE_TO_VIP2')

日常项目中,在store有多个状态需要管理的时候,一般来说是应该要开启namespaced的,这样子能够使我们的代码能够有更强的封装性以及更少的耦合。

补充知识:Vuex 模块化+命名空间后, 如何调用其他模块的 state, actions, mutations, getters ?

由于 Vuex 使用了单一状态树,应用的所有状态都包含在一个大对象中。那么,随着应用的不断扩展,store 会变得非常臃肿。

为了解决这个问题,Vuex 允许我们把 store 分 module(模块)。每一个模块包含各自的状态、mutation、action 和 getter。

那么问题来了, 模块化+命名空间之后, 数据都是相对独立的, 如果想在模块 A 调用 模块 B 的state, actions, mutations, getters, 该肿么办?

假设有这么两个模块:

模块A:

import api from '~api'

const state = {
  vip: {},
}

const actions = {
  async ['get']({commit, state, dispatch}, config = {}) {
    try {
      const { data: { code, data } } = await api.post('vip/getVipBaseInfo', config)
      if (code === 1001) commit('receive', data)
    } catch(error) { console.log(error) }
  }
}

const mutations = {
  ['receive'](state, data) {
    state.vip = data
  }
}

const getters = {
  ['get'](state) {
    return state.vip
  },
}

export default {
  namespaced: true,
  state,
  actions,
  mutations,
  getters
}

模块B:

import api from '~api'

const state = {
  shop: {},
}

const actions = {
  async ['get']({commit, state, dispatch}, config = {}) {
    try {
      const { data: { code, data } } = await api.post('shop/getShopBaseInfo', config)
      if (code === 1001) commit('receive', data)
    } catch(error) { console.log(error) }
  }
}

const mutations = {
  ['receive'](state, data) {
    state.shop = data
  }
}

const getters = {
  ['get'](state) {
    return state.shop
  },
}

export default {
  namespaced: true,
  state,
  actions,
  mutations,
  getters
}

假设模块 B 的 actions 里, 需要用模块 A 的 state 该怎么办?

const actions = {
  async ['shop'](store, config = {}) {
    const { commit, dispatch, state, rootState } = store
    console.log(rootState) // 打印根 state
    console.log(rootState.vip) // 打印其他模块的 state
    try {
      const { data: { code, data } } = await api.post('shop/getShopBaseInfo', config)
      if (code === 1001) commit('receive', data)
    } catch(error) { console.log(error) }
  }
}

我们来看下上面的代码, actions 中的 shop 方法, 有 2 个参数, 第一个是 store, 第二个是 dispatch 调用时传过来的参数

store 这个对象又包含了 4 个键, 其中 commit 是调用 mutations 用的, dispatch 是调用 actions 用的, state 是当前模块的 state, 而 rootState 是根 state,

既然能拿到根 state, 想取其他模块的 state 是不是就很简单了...?

假设模块 B 的 actions 里, 需要调用模块 A 的 actions 该怎么办?

const actions = {
  async ['shop'](store, config = {}) {
    const { commit, dispatch, state, rootState } = store
    try {
      const { data: { code, data } } = await api.post('shop/getShopBaseInfo', config, 'get')
      if (code === 1001) commit('receive', data) // 调用当前模块的 mutations
      dispatch('vip/get', {}, {root: true}) // 调用其他模块的 actions
    } catch(error) { console.log(error) }
  }
}

上面的代码中dispatch('vip/vip', {}, {root: true})就是在模块 B 调用 模块 A 的 actions,

有 3 个参数, 第一个参数是其他模块的 actions 路径, 第二个是传给 actions 的数据, 如果不需要传数据, 也必须预留, 第三个参数是配置选项, 申明这个 acitons 不是当前模块的

假设模块 B 的 actions 里, 需要调用模块 A 的 mutations 该怎么办?

const actions = {
  async ['shop'](store, config = {}) {
    const { commit, dispatch, state, rootState } = store
    try {
      const { data: { code, data } } = await api.post('shop/getShopBaseInfo', config)
      if (code === 1001) commit('receive', data) // 调用当前模块的 mutations
      commit('vip/receive', data, {root: true}) // 调用其他模块的 mutations
    } catch(error) { console.log(error) }
  }
}

上面的代码中commit('vip/receive', {}, {root: true})就是在模块 B 调用 模块 A 的 mutations,

有 3 个参数, 第一个参数是其他模块的 mutations 路径, 第二个是传给 mutations 的数据, 如果不需要传数据, 也必须预留, 第三个参数是配置选项, 申明这个 mutations 不是当前模块的

假设模块 B 的 actions 里, 需要用模块 A 的 getters 该怎么办?

const actions = {
  async ['shop'](store, config = {}) {
    const { commit, dispatch, state, rootState, rootGetters } = store
    console.log(rootGetters['vip/get']) // 打印其他模块的 getters
    try {
      const { data: { code, data } } = await api.post('shop/getShopBaseInfo', config)
      if (code === 1001) commit('receive', data)
    } catch(error) { console.log(error) }
  }
}

我们来看下上面的代码, 相比之前的代码, store 又多了一个键: rootGetters

rootGetters 就是 vuex 中所有的 getters, 你可以用 rootGetters['xxxxx'] 来取其他模块的getters

以上这篇vuex 多模块时 模块内部的mutation和action的调用方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript学习之闭包分析
Dec 02 Javascript
js String对象中常用方法小结(字符串操作)
Jan 27 Javascript
jquery mobile实现拨打电话功能的几种方法
Aug 05 Javascript
javascript的alert box在java中如何显示多行
May 18 Javascript
基于Bootstrap漂亮简洁的CSS3价格表(附源码下载)
Feb 28 Javascript
jQuery remove()过滤被删除的元素(推荐)
Jul 18 jQuery
JS设置随机出现2个数字的实例代码
Jul 19 Javascript
webpack 模块热替换原理
Apr 09 Javascript
JS的Ajax与后端交互数据的实例
Aug 08 Javascript
JavaScript栈和队列相关操作与实现方法详解
Dec 07 Javascript
解决layer 关闭当前弹窗 关闭遮罩层 input值获取不到的问题
Sep 25 Javascript
JavaScript ES 模块的使用
Nov 12 Javascript
在Vuex中Mutations修改状态操作
Jul 24 #Javascript
Vue自动构建发布脚本的方法示例
Jul 24 #Javascript
Vue-CLI 3 scp2自动部署项目至服务器的方法
Jul 24 #Javascript
vue data对象重新赋值无效(未更改)的解决方式
Jul 24 #Javascript
VUE项目axios请求头更改Content-Type操作
Jul 24 #Javascript
vue+axios全局添加请求头和参数操作
Jul 24 #Javascript
vue在响应头response中获取自定义headers操作
Jul 24 #Javascript
You might like
qq登录,新浪微博登录接口申请过程中遇到的问题
2014/07/22 PHP
php技术实现加载字体并保存成图片
2015/07/27 PHP
浅谈tudou土豆网首页图片延迟加载的效果
2010/06/23 Javascript
JavaScript Tips 使用DocumentFragment加快DOM渲染速度
2010/06/28 Javascript
理解Javascript_06_理解对象的创建过程
2010/10/15 Javascript
jQuery的12招常用技巧分享
2011/08/08 Javascript
js下拉菜单语言选项简单实现
2013/09/23 Javascript
Egret引擎开发指南之运行项目
2014/09/03 Javascript
基于jQuery.Hz2Py.js插件实现的汉字转拼音特效
2015/05/07 Javascript
JS实现淡蓝色简洁竖向Tab点击切换效果
2015/10/06 Javascript
jQuery ajax分页插件实例代码
2016/01/27 Javascript
一次$.getJSON不执行的简单记录
2016/07/19 Javascript
javascript实现无法关闭的弹框
2016/11/27 Javascript
微信小程序页面传值实例分析
2017/04/19 Javascript
Vue.js 十五分钟入门图文教程
2018/09/12 Javascript
vue组件中watch props根据v-if动态判断并挂载DOM的问题
2019/05/12 Javascript
vue学习笔记之Vue中css动画原理简单示例
2020/02/29 Javascript
vue中改变滚动条样式的方法
2020/03/03 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
2020/05/12 Javascript
Js数组扁平化实现方法代码总汇
2020/11/11 Javascript
[01:17:12]职来职往完美电竞专场
2014/09/18 DOTA
详解Python中for循环的使用方法
2015/05/14 Python
python 队列详解及实例代码
2016/10/18 Python
Python 函数基础知识汇总
2018/03/09 Python
Ibatis如何调用存储过程
2015/05/15 面试题
工作自我评价怎么写
2014/01/29 职场文书
大学班级计划书
2014/04/29 职场文书
我读书我快乐演讲稿
2014/05/07 职场文书
学雷锋活动倡议书
2014/08/30 职场文书
2014年乡镇领导个人整改措施
2014/09/19 职场文书
2015年学校党建工作总结
2015/05/19 职场文书
何玥事迹观后感
2015/06/16 职场文书
2015年党建工作汇报材料
2015/06/25 职场文书
《中华上下五千年》读后感3篇
2019/11/29 职场文书
Python机器学习之逻辑回归
2021/05/11 Python
Oracle 触发器trigger使用案例
2022/02/24 Oracle