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调用iframe实现打印页面内容的方法
Mar 04 Javascript
3种js实现string的substring方法
Nov 09 Javascript
利用jquery制作滚动到指定位置触发动画
Mar 26 Javascript
详解vue-router基本使用
Apr 18 Javascript
详解从零搭建 vue2 vue-router2 webpack3 工程
Nov 22 Javascript
解析Json字符串的三种方法日常常用
May 02 Javascript
微信小程序scroll-view仿拼多多横向滑动滚动条
Apr 21 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
Sep 14 Javascript
从零撸一个pc端vue的ui组件库( 计数器组件 )
Aug 08 Javascript
vue router动态路由设置参数可选问题
Aug 21 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
Dec 06 Javascript
JavaScript设计模式--简单工厂模式定义与应用案例详解
May 23 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初学者头痛的十四个问题
2006/07/12 PHP
不用mod_rewrite直接用php实现伪静态化页面代码
2008/10/04 PHP
php简单提示框alert封装函数
2010/08/08 PHP
PHP学习笔记之三 数据库基本操作
2011/01/17 PHP
如何用php生成扭曲及旋转的验证码图片
2013/06/07 PHP
Linux下安装PHP MSSQL扩展教程
2014/10/24 PHP
PHP生成短网址的思路以及实现方法的详解
2019/03/25 PHP
js控制div及网页相关属性的代码
2009/12/19 Javascript
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
2011/02/23 Javascript
面向对象Javascript核心支持代码分享
2012/05/23 Javascript
JavaScript全排列的六种算法 具体实现
2013/06/29 Javascript
js分页代码分享
2014/04/28 Javascript
JavaScript加入收藏夹功能(兼容IE、firefox、chrome)
2014/05/05 Javascript
jQuery的选择器中的通配符[id^='code']或[name^='code']及jquery选择器总结
2015/12/24 Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
2016/01/19 Javascript
jQuery+PHP+MySQL实现无限级联下拉框效果
2016/02/19 Javascript
详解从Node.js的child_process模块来学习父子进程之间的通信
2017/03/27 Javascript
JavaScript函数节流的两种写法
2017/04/07 Javascript
JS实现数组去重,显示重复元素及个数的方法示例
2019/01/21 Javascript
[01:31:03]DOTA2完美盛典全回顾 见证十五项大奖花落谁家
2017/11/28 DOTA
Python使用MONGODB入门实例
2015/05/11 Python
Python中几种属性访问的区别与用法详解
2018/10/10 Python
python实现剪切功能
2019/01/23 Python
Python字符串通过'+'和join函数拼接新字符串的性能测试比较
2019/03/05 Python
Django框架自定义session处理操作示例
2019/05/27 Python
python读取word 中指定位置的表格及表格数据
2019/10/23 Python
python怎么对数字进行过滤
2020/07/05 Python
python获取整个网页源码的方法
2020/08/03 Python
中国最大的名表商城:万表网
2016/08/29 全球购物
美国在线乐器和设备商店:Musician’s Friend
2018/07/06 全球购物
竞聘上岗演讲稿范文
2014/01/10 职场文书
银行类自荐信
2014/02/04 职场文书
环卫工人节活动总结
2014/08/29 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
省级三好学生主要事迹材料
2015/11/03 职场文书
土木工程生产实习心得体会
2016/01/22 职场文书