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 相关文章推荐
jquery蒙版控件实现代码
Dec 08 Javascript
基于jquery的bankInput银行卡账号格式化
Aug 22 Javascript
如何学习Javascript入门指导
Nov 01 Javascript
JS判断变量是否为空判断是否null
Jul 25 Javascript
JavaScript数组前面插入元素的方法
Apr 06 Javascript
jQuery动态星级评分效果实现方法
Aug 06 Javascript
全面了解JavaScript对象进阶
Jul 19 Javascript
jQuery实现淡入淡出的模态框
Feb 09 Javascript
基于JS代码实现简单易用的倒计时 x 天 x 时 x 分 x 秒效果
Jul 13 Javascript
vue2.0页面前进刷新回退不刷新的实现方法
Jul 31 Javascript
jQuery 查找元素操作实例小结
Oct 02 jQuery
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 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
PHP 编程请选择正确的文本编辑软件
2006/12/21 PHP
php递归获取目录内文件(包含子目录)封装类分享
2013/12/25 PHP
PHPExcel简单读取excel文件示例
2016/05/26 PHP
PHP实现读取文件夹及批量重命名文件操作示例
2019/04/15 PHP
PHP框架实现WebSocket在线聊天通讯系统
2019/11/21 PHP
PHP7 参数处理机制修改
2021/03/09 PHP
jQuery 位置函数offset,innerWidth,innerHeight,outerWidth,outerHeight,scrollTop,scrollLeft
2010/03/23 Javascript
S2SH整合JQuery+Ajax实现登录验证功能实现代码
2013/01/30 Javascript
jquery submit ie6下失效的原因分析及解决方法
2013/11/15 Javascript
jquery实现图片翻页效果
2013/12/23 Javascript
$.each与$().each的区别示例介绍
2014/03/20 Javascript
jQuery实现根据类型自动显示和隐藏表单
2015/03/18 Javascript
跟我学习javascript的this关键字
2020/05/28 Javascript
你一定会收藏的Nodejs代码片段
2016/02/04 NodeJs
利用JQuery写一个简单的异步分页插件
2016/03/07 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
2016/05/10 Javascript
Javascript this 函数深入详解
2016/12/13 Javascript
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
Java设计中的Builder模式的介绍
2018/03/22 Javascript
Vue+Element实现表格编辑、删除、以及新增行的最优方法
2019/05/28 Javascript
6种JavaScript继承方式及优缺点(小结)
2020/02/06 Javascript
vue如何使用外部特殊字体的操作
2020/07/30 Javascript
Python发送http请求解析返回json的实例
2018/03/26 Python
python 模拟贷款卡号生成规则过程解析
2019/08/30 Python
django框架中间件原理与用法详解
2019/12/10 Python
西班牙创意礼品和小工具网上商店:Curiosite
2016/07/26 全球购物
努比亚手机官网:nubia
2016/10/06 全球购物
实习生体会的自我评价范文
2013/11/28 职场文书
制药工程专业个人求职自荐信
2014/01/25 职场文书
委托书模板
2014/04/04 职场文书
中班下学期个人工作总结
2015/02/12 职场文书
质量保证书格式
2015/02/27 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
祝福语集锦:给满月宝宝的祝福语
2019/11/20 职场文书
python opencv检测直线 cv2.HoughLinesP的实现
2021/06/18 Python
Canvas绘制像素风图片的示例代码
2021/09/25 HTML / CSS