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 相关文章推荐
显示js对象所有属性和方法的函数
Oct 16 Javascript
JavaScript中出现乱码的处理心得
Dec 24 Javascript
jQuery EasyUI API 中文文档 - Spinner微调器使用
Oct 21 Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 Javascript
js实现完全自定义可带多级目录的网页鼠标右键菜单方法
Feb 28 Javascript
第九章之路径分页标签与徽章组件
Apr 25 Javascript
基于jquery实现左右上下移动效果
May 02 jQuery
如何把vuejs打包出来的文件整合到springboot里
Jul 26 Javascript
jQuery+css last-child实现选择最后一个子元素操作示例
Dec 10 jQuery
如何为你的JS项目添加智能提示与类型检查详解
Mar 12 Javascript
JS实现简易留言板增删功能
Feb 08 Javascript
Vue中nprogress页面加载进度条的方法实现
Nov 13 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
PHP读取数据库并按照中文名称进行排序实现代码
2013/01/29 PHP
PHP无法访问远程mysql的问题分析及解决
2013/05/16 PHP
PHP 循环删除无限分类子节点的实现代码
2013/06/21 PHP
学习php分页代码实例
2013/10/24 PHP
php简单实现短网址(短链)还原的方法(测试可用)
2016/05/09 PHP
js实现ASP分页函数 HTML分页函数
2006/09/22 Javascript
解放web程序员的输入验证
2006/10/06 Javascript
javascript Prototype 对象扩展
2009/05/15 Javascript
关于Mozilla浏览器不支持innerText的解决办法
2011/01/01 Javascript
windows系统下简单nodejs安装及环境配置
2013/01/08 NodeJs
js中Image对象以及对其预加载处理示例
2013/11/20 Javascript
JavaScript中的定时器之Item23的合理使用
2015/10/30 Javascript
最实用的jQuery分页插件
2016/10/09 Javascript
jQuery实现自动调用和触发某个事件的方法
2016/11/18 Javascript
js设计模式之单例模式原理与用法详解
2019/08/15 Javascript
在vue中实现嵌套页面(iframe)
2020/07/30 Javascript
Python获取单个程序CPU使用情况趋势图
2015/03/10 Python
Python实现控制台输入密码的方法
2015/05/29 Python
基于Python函数的作用域规则和闭包(详解)
2017/11/29 Python
python使用jieba实现中文分词去停用词方法示例
2018/03/11 Python
python 移除字符串尾部的数字方法
2018/07/17 Python
对Python3+gdal 读取tiff格式数据的实例讲解
2018/12/04 Python
python爬虫爬取微博评论案例详解
2019/03/27 Python
详解Python 解压缩文件
2019/04/09 Python
python列表的逆序遍历实现
2020/04/20 Python
详解用Python调用百度地图正/逆地理编码API
2020/07/02 Python
Super-Pharm波兰:药房和香水在一个地方
2020/08/18 全球购物
新加坡最早生产电动滑板车的制造商之一:FunsToTheFore
2020/09/08 全球购物
介绍一下如何利用路径遍历进行攻击及如何防范
2014/01/19 面试题
外贸专业求职信
2014/03/09 职场文书
农村文化活动总结
2014/08/28 职场文书
2014年音乐教师工作总结
2014/12/03 职场文书
幼儿园辞职信范文
2015/02/27 职场文书
针对吵架老公保证书
2015/05/08 职场文书
小组口号霸气押韵
2015/12/24 职场文书
详解Laravel制作API接口
2021/05/31 PHP