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 相关文章推荐
Array对象方法参考
Oct 03 Javascript
jquery radio 操作代码
Mar 16 Javascript
Javascript 读取操作Sql中的Xml字段
Oct 09 Javascript
一个JavaScript递归实现反转数组字符串的实例
Oct 14 Javascript
jquery插件uploadify实现带进度条的文件批量上传
Dec 13 Javascript
JavaScript中字符串与Unicode编码互相转换的实现方法
Dec 18 Javascript
详解javascript跨浏览器事件处理程序
Mar 27 Javascript
微信小程序之网络请求简单封装实例详解
Jun 28 Javascript
小程序实现留言板
Nov 02 Javascript
vue-cli随机生成port源码的方法
Sep 02 Javascript
微信小程序wx.request的简单封装
Nov 13 Javascript
Vue路由权限控制解析
Nov 09 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中经典方法实现判断多维数组是否为空
2011/10/23 PHP
php 把数字转换成汉字的代码
2015/07/21 PHP
Laravel中间件实现原理详解
2016/10/09 PHP
php rmdir使用递归函数删除非空目录实例详解
2016/10/20 PHP
PHP实现将base64编码字符串转换成图片示例
2018/06/22 PHP
在Laravel 中实现是否关注的示例
2019/10/22 PHP
javascript cookie操作类的实现代码小结附使用方法
2010/06/02 Javascript
Javascript调用C#代码
2011/01/17 Javascript
JavaScript 的继承
2011/10/01 Javascript
nodejs事件的监听与触发的理解分析
2015/02/12 NodeJs
webpack配置文件和常用配置项介绍
2017/04/28 Javascript
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
JavaScript基础心法 数据类型
2018/03/05 Javascript
Angular5.0 子组件通过service传递值给父组件的方法
2018/07/13 Javascript
vue项目中添加单元测试的方法
2018/07/21 Javascript
基于 Vue 的 Electron 项目搭建过程图文详解
2020/07/22 Javascript
JavaScript前端开发时数值运算的小技巧
2020/07/28 Javascript
[10:14]2018DOTA2国际邀请赛寻真——paiN Gaming不仅为自己而战
2018/08/14 DOTA
如何解决django配置settings时遇到Could not import settings 'conf.local'
2014/11/18 Python
深入浅析ImageMagick命令执行漏洞
2016/10/11 Python
Python判断某个用户对某个文件的权限
2016/10/13 Python
Flask之flask-script模块使用
2018/07/26 Python
tensorflow: variable的值与variable.read_value()的值区别详解
2018/07/30 Python
Python3enumrate和range对比及示例详解
2019/07/13 Python
Python爬取腾讯视频评论的思路详解
2019/12/19 Python
Python3.7将普通图片(png)转换为SVG图片格式(网站logo图标)动起来
2020/04/21 Python
Canvas系列之滤镜效果
2019/02/12 HTML / CSS
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
新西兰领先的鞋类和靴子网上商城:Merchant 1948
2017/09/08 全球购物
英国复古和经典球衣网站:Vintage Football Shirts
2018/10/05 全球购物
建筑工程实习自我鉴定
2013/09/19 职场文书
学雷锋活动总结范文
2014/04/25 职场文书
2014年安全生产目标责任书
2014/07/23 职场文书
部队反四风对照检查材料
2014/09/26 职场文书
2014年综治维稳工作总结
2014/11/17 职场文书
离婚协议书格式
2015/01/26 职场文书