Vuex 模块化使用详解

前言 上回我们说了一下 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 上面,大家可以去看一下,要是项目中有啥不明白的或者我说的有问题的,欢迎大家留言指正。

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

(0)

相关推荐

  • Vue组件间通信 Vuex的用法解析

    上回说到Vue组件间通讯,最后留了一个彩蛋~~~Vuex.Vuex是另一种组件通讯的方法,这节来说说Vuex(store仓库). 首先Vuex需要安装,安装的方式有很多,在这里就不一一细说了.我是通过npm方式安装的: npm install vuex --save 安装好之后需要再main.js里全局引入: import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)new Vue({el:'#app',store,components

  • 详解Vuex下Store的模块化拆分实践

    前言 最近的项目用到了 vue.js + vuex + vue-router 全家桶,版本为 >2.0,在搞Store的时候发现,圈子里大部分关于vuex的文章都是比较基础的Demo搭建方式,很少有涉及到比较复杂的模块化拆分的Store实践,而且事实上也有朋友在实践中问到过这方面的内容,vuex自身提供了模块化的方式,因此在这里总结一下我自己在项目里的心得. 模块化拆分 vue.js的项目文件结构在这里就不说了,大家可以通过vue-cli初始化项目,脚手架会为你搭建一个start项目的最佳实践.

  • vuex 动态注册方法 registerModule的实现

    Vuex(2.3.0+)可以用store.registerModule方法在进入路由时进行注册,离开路由时候销毁 actions, mutations, getters, state,在一定范围内相同名称不会被覆写 例子 index.js 传this 的写法 module.exports = { install(_this) { _this.$store.registerModule(['abc'], { namespaced: true, state: { rightTest: 999 },

  • 详解vuex的简单todolist例子

    一个简单的vuex应用的小例子,一段自己的学习记录. todolist就是一个简单的输入框,一个按钮,一个文本显示区域,可以逐条进行删除. 1.在用vue-cli生成好的HelloWorld.vue文件中直接写代码,先删除所有的自带代码 <template> <div class="hello"> <input type="text"> <button>增加事项</button> <ul> &l

  • vuex vue简单使用知识点总结

    vue概念:vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便 整个程序中的任何组件直接获取或修改我们的公共数据: 配置vuex的步骤: 1.运行cnpm i vuex -S 2.导包 import Vuex from 'vuex' 3.将vuex注册到vue中 Vue.use(Vuex) 4.new Vuex.Store() 实例,得到一个 数据仓储对象 var store = new Vuex.Store({ state: { // 大家可以把

  • Vuex 模块化使用详解

    前言 上回我们说了一下 vuex 的简单使用,最后面的时候有说了,由于使用单一状态树,应用的所有状态会集中到一个比较大的对象.当应用变得非常复杂时,store 对象就有可能变得相当臃肿. 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module).每个模块拥有自己的 state.mutation.action.getter.甚至是嵌套子模块--从上至下进行同样方式的分割,今天我们也来简单了解一下他的使用,深入学习可能还是要去看官方文档 1 文件结构 文件结构的话,模块化的使用

  • Vuex总体案例详解

    目录 一.简介 二.优点 三.使用步骤 1. 安装Vuex 2. 引用Vuex 3. 创建仓库Store 四.包含模块 1. State 2. Getters 3. Mutations 4. Action 5. Modules 五.Vuex最最简单的项目实例 1. 存储数据 2. 获取数据 3. store文件目录结构 index.js state.js mutations.js actions.js getters.js 4. 使用store 一.简介 我们来看看对 Vuex 比较专业的介绍:

  • Vue学习之Vuex的使用详解

    目录 简介 优缺点 优点 缺点 使用场景 示例 安装Vuex并引入 1.安装vuex 2.编写vuex的store 3.main.js引入CounterStore.js 业务代码 测试 简介 说明 本文介绍Vue的插件:Vuex.包括:优缺点.使用场景.示例. 官网 官网文档 API vuex-store 优缺点 优点 1.响应式 属于 vue 生态一环,,能够触发响应式的渲染页面更新. (localStorage 就不会) 2.可预测的方式改变数据 避免数据污染 3.无需转换数据 JS 原生的

  • nodejs express路由匹配控制及Router模块化使用详解

    目录 路由控制匹配 Router模块化路由 使用方式 对比app上的路由 总结 路由控制匹配 本文主要分析下express的核心功能路由的使用. express路由的匹配规则: 支持模糊匹配,同一个路由可能命中多个定义的路由 router.get("/user/*",(req,res,next)=>{ console.log("====demo====") }) router.get("/user/list",(req,res,next)=

  • Vuex 进阶之模块化组织详解

    上上篇:Vuex 入门 上一篇:Vuex 提升 自制vuex LOGO 前两篇讲解了一下 Vuex 的基本使用方法,可是在实际项目中那么写肯定是不合理的,如果组件太多,不可能把所有组件的数据都放到一个 store.js 中的,所以就需要模块化的组织 Vuex,首先看一下 项目结构. 项目结构 一.首先执行以下命令: vue init webpack-simple vuex-demo cd vuex-demo npm install npm install vuex -S npm run dev

  • Vue的状态管理vuex使用方法详解

    引入vuex 当访问数据对象时,一个 Vue 实例只是简单的代理访问.所以,如果有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享 const sourceOfTruth = {} const vmA = new Vue({ data: sourceOfTruth }) const vmB = new Vue({ data: sourceOfTruth }) 现在当 sourceOfTruth 发生变化,vmA 和 vmB 都将自动的更新引用它们的视图.子组件们的每个实例也会

  • Javascript模块化编程详解

    模块化编程是一种非常常见Javascript编程模式.它一般来说可以使得代码更易于理解,但是有许多优秀的实践还没有广为人知. 基础 我们首先简单地概述一下,自从三年前Eric Miraglia(YUI的开发者)第一次发表博客描述模块化模式以来的一些模块化模式.如果你已经对于这些模块化模式非常熟悉了,大可以直接跳过本节,从"进阶模式"开始阅读. 匿名闭包 这是一种让一切变为可能的基本结构,同时它也是Javascript最棒的特性.我们将简单地创建一个匿名函数并立即执行它.所有的代码将跑在

  • 自定义vue全局组件use使用、vuex的使用详解

    自定义vue全局组件use使用(解释vue.use()的原理) 我们在前面学习到是用别人的组件:Vue.use(VueRouter).Vue.use(Mint)等等. 其实使用的这些都是全局组件,这里我们就来讲解一下怎么样定义一个全局组件,并解释vue.use()的原理 而我们再用Axios做交互,则不能使用Vue.use(Axios),因为Axios没有install自定义一个全局Loading组件,并使用: 总结目录: |-components |-loading |-index.js 导出

  • vue 搭建后台系统模块化开发详解

    本文主要介绍了vue 搭建后台系统模块化开发,分享给大家,具体如下: 效果 目录结构 ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── confi

  • vue全局组件与局部组件使用方法详解

    vue全局/局部注册,以及一些混淆的组件 main.js入口文件的一些常用配置, 在入口文件上定义的public.vue为全局组件,在这里用的是pug模版 .wraper 的形式相当于<div class=wraper></div> -main.js文件 **main.js入口文件的内容** import Vue from 'vue' import App from './App' import router from './router' // 引入公用组件的vue文件 他暴漏的

随机推荐