Vuex 模块化使用详解


Posted in Javascript onJuly 31, 2019

前言 上回我们说了一下 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 文件中引入这些模块,直接

import moduleA from './modules/moduleA/index'
import moduleB from './modules/moduleB';

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
    moduleA,
    moduleB,
  }
});

2 模块的局部状态对象的定义

模块内部的 getter,mutation 和 action,他们方法接收的参数会和根状态的不一样,我们一个一个来

getter

getter 的话,他会有三个参数,第一个是模块内的 state,第二个是 模块内的 getters,第三个是根节点状态 rootState,

const getters = {
 bFullName: (state, getters, rootState) => `full${state.bName}`
}

mutation

mutation 里面的回调函数传入的第一个参数也是 模块内的 state,其他和根状态定义的时候一样

const mutations = {
 // 这里的 `state` 对象是模块的局部状态
 SET_B_NAME(state, payload) {
  debugger
  state.bName = payload.name;
 }
}

action

最后的 action 的话,他传入还是只有 context 对象,然后咧,这个对象里面的 state 属性指模块内的状态,rootState 指根状态,如下

const actions = {
 ASYNC_SET_NAME({ state, commit, rootState }, payload) {
  setTimeout(() => {
   state.bName = 'asyncName'
  }, 4000)
 }
}

3 使用

3.1 state 获取

这个的话要在原来状态名前面加一个模块名才能放到到模块内的对象。具体如下

// 原先的基础上加个模块名
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,
export default {
 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
})

// 同理 mapAction mapMutation 也可以这个样子
...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 函数中,具体如下:

const actions = {
  // 模块内 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 上面,大家可以去看一下,要是项目中有啥不明白的或者我说的有问题的,欢迎大家留言指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery replace 字符替换实现代码
Dec 02 Javascript
Javascript计算时间差的函数分享
Jul 04 Javascript
javascript与cookie 的问题详解
Nov 11 Javascript
js关于精确计算和数值格式化以及直接引js文件
Jan 28 Javascript
javascript使用输出语句实现网页特效代码
Aug 06 Javascript
jquery实现的动态回到顶部特效代码
Oct 28 Javascript
javascript性能优化之DOM交互操作实例分析
Dec 12 Javascript
javascript的BOM
May 03 Javascript
从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例
Apr 13 Javascript
jquery实现楼层滚动效果
Jan 01 jQuery
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
Sep 13 Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
Nov 21 Javascript
判断“命令按钮”是否被鼠标单击详解
Jul 31 #Javascript
express框架下使用session的方法
Jul 31 #Javascript
ES6中异步对象Promise用法详解
Jul 31 #Javascript
JS实现在线ps功能详解
Jul 31 #Javascript
ES6中定义类和对象的方法示例
Jul 31 #Javascript
Vue+Koa2 打包后进行线上部署的教程详解
Jul 31 #Javascript
简述vue-cli中chainWebpack的使用方法
Jul 30 #Javascript
You might like
Yii使用ajax验证显示错误messagebox的解决方法
2014/12/03 PHP
Yii框架函数简单用法分析
2019/09/09 PHP
yii框架结合charjs统计上一年与当前年数据的方法示例
2020/04/04 PHP
JavaScript For Beginners(转载)
2007/01/05 Javascript
jQuery遍历Form示例代码
2013/09/03 Javascript
js识别不同浏览器基于userAgent做判断
2014/07/29 Javascript
jquery仿百度百科底部浮动导航特效
2015/08/08 Javascript
AngularJS中$watch和$timeout的使用示例
2016/09/20 Javascript
Angular2生命周期钩子函数的详细介绍
2017/07/10 Javascript
Angular利用trackBy提升性能的方法
2018/01/26 Javascript
通过javascript实现段落的收缩与展开
2019/06/26 Javascript
layui实现三级导航菜单
2019/07/26 Javascript
Angular8 简单表单验证的实现示例
2020/06/03 Javascript
浅谈JavaScript中你可能不知道URL构造函数的属性
2020/07/13 Javascript
[45:10]NB vs Liquid Supermajor小组赛 A组胜者组决赛 BO3 第二场 6.2
2018/06/04 DOTA
[01:00:14]DOTA2官方TI8总决赛纪录片 真视界True Sight
2019/01/16 DOTA
浅谈django中的认证与登录
2016/10/31 Python
python的格式化输出(format,%)实例详解
2018/06/01 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
Python生成指定数量的优惠码实操内容
2019/06/18 Python
pandas 对group进行聚合的例子
2019/12/27 Python
Eclipse配置python默认头过程图解
2020/04/26 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
Python读取ini配置文件传参的简单示例
2021/01/05 Python
纯CSS3单页切换导航菜单界面设计的简单实现
2016/08/16 HTML / CSS
出口公司经理求职简历中的自我评价
2013/10/13 职场文书
英文版销售经理个人求职信
2013/11/20 职场文书
境外导游求职信
2014/02/27 职场文书
国窖1573广告词
2014/03/21 职场文书
环境保护建议书
2014/08/26 职场文书
三好学生个人总结
2015/02/15 职场文书
党员考试作弊检讨书1000字
2015/02/16 职场文书
基层党支部承诺书
2015/04/30 职场文书
诗词赏析-(浣溪沙)
2019/08/13 职场文书
漫画「处刑少女的生存之道」第3卷封面公开
2022/03/21 日漫
vue3引入highlight.js进行代码高亮的方法实例
2022/04/08 Vue.js