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

前言

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

模块化拆分

vue.js的项目文件结构在这里就不说了,大家可以通过vue-cli初始化项目,脚手架会为你搭建一个start项目的最佳实践。

默认你已经搭架好了一个项目,而且需要建立或者已经是一个复杂的Store,但是还没有进行模块拆分,你可以尝试对其进行模块拆分,当然在一开始你不必一定需要这么做。

1. 安装Vuex,建立文件结构

在项目根目录下安装vuex:

npm install vuex -S

安装完毕后,在项目的src文件夹下新建一个store文件夹,并且分别在其中新建modules,actions,mutations,getters,constants子文件夹和一个index.js文件。

目录结构如下:

└─ demo/
  ├── build/
  ├── config/
  ├── node_modules/
  ├── src/
  │  ├── assets/
  │  ├── components/
  │  ├── store/
  │  │  ├── actions/
  │  │  │  ├──aAction.js
  │  │  │  ├──bAction.js
  │  │  │  └──cAction.js
  │  │  ├── constants/
  │  │  │  └── types.js
  │  │  ├── getters/
  │  │  │  └── aGetter.js
  │  │  ├── modules/
  │  │  │  ├── aModules.js
  │  │  │  ├── bModules.js
  │  │  │  ├── cModules.js
  │  │  │  └── index.js
  │  │  ├── mutations/
  │  │  │  ├── aMutation.js
  │  │  │  ├── bMutation.js
  │  │  │  └── cMutation.js
  │  │  └── index.js
  │  ├── App.vue
  │  └── main.js
  ├── static/
  ├── utils/
  ├── test/
  └── index.html

好了,基本的文件结构大概就是上面?这样的。

2. 编写模块A

在编写模块之前,首先设定一些type类,例如:

types.js

module.exports = keyMirror({

  FETCH_LIST_REQUEST: null,
  FETCH_LIST_SUCCESS: null,
  FETCH_LISR_FAILURE: null

})

function keyMirror (obj) {
 if (obj instanceof Object) {
  var _obj = Object.assign({}, obj)
  var _keyArray = Object.keys(obj)
  _keyArray.forEach(key => _obj[key] = key)
  return _obj
 }
}

上面自己实现keyMirror的方法,大家也可以使用下面这个包:

https://github.com/STRML/keyMirror

keyMirror的作用就是下面这个一个形式?,作用其实也不是很大:

Input: {key1: null, key2: null}

Output: {key1: key1, key2: key2}

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
  fetchList ({ commit, state }, param) {
    commit(FETCH_LIST_REQUEST)
    axios.get('http://youdomain.com/list')
     .then(function (response) {
      commit(FETCH_LIST_SUCCESS, {
        data: response.data
      })
      console.log(response);
     })
     .catch(function (error) {
      commit(FETCH_LIST_FAILURE, {
        error: error
      })
      console.log(error);
     });
  }
}

getters/aGetter.js

export const = fetchListGetter = {
  hotList (state) {
    return state.list.data.slice(0, 10)
  }
}

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'

export const fetchListMutation = {
  [FETCH_LIST_REQUEST] (state) {
    state.isFetching = true
  },
  [FETCH_LIST_SUCCESS] (state, action) {
    state.isFetching = false
    state.data = action.data
    state.lastUpdated = (new Date()).getTime()
  },
  [FETCH_LIST_FAILURE] (state, action) {
    state.isFetching = false
    state.error = action.error
  }
}

modules/aModule.js

import { fetchListAction } from '../actions/aAction'
import { fetchListGetter } from '../getters/aGetter'
import { fetchListMutation } from '../mutations/aMutation'

export const list = {
  state: {
    isFetching: false,
    data: []
  }
  actions: fetchListAction,
  getters: fetchListGetter,
  mutations: fetchListMutation
}

modules/index.js

import { list } from './aModule'

module.exports = {
  list: list
}

3. 挂载store

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import { list } from './modules'

Vue.use(Vuex)

const store = new Vuex.Store({
 modules: {
  list: list

 },
 plugins: [createLogger()],
 strict: process.env.NODE_ENV !== 'production'
})

if (module.hot) {
 module.hot.accept(['./mutations'], () => {
  const newMutations = require('./mutations').default

  store.hotUpdate({
   mutations: newMutations
  })
 })
}

export default store

4. store注入vue实例

main.js

 ····
import store from './store'

 ···· 

var vue = new Vue({
 store,

 ···· 

})

vue.$mount('#app')

5. 在Component中使用

Vuex 提供了组件中使用的mapState,mapAction,mapGetter方法,因此可以很方便的调用。

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
  ·······
  methods: {
    ...mapActions([
      'fetchList'
    ])
  },
  computed: {
    ...mapState{
      list: state => state.list
    },
    ...mapGetters{[
      'hotList'
    ]}
  }
}
</script>
<style>
  ·······
</style>

复用模块

模块化拆分之后可以实现较为复杂的数据流,特别地,如果对action和mutation稍加改造,就可以复用模块:
比如我们在Example.vue中发起Action:

Example.vue

<template>

 ·········

</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
module.exports = {
  ·······
  mounted () {
    this.fetchList({
      request: 'week'
    })
  },
  methods: {
    ...mapActions([
      'fetchList'
    ])
  },
  computed: {
    ...mapState{
      list: state => state.list
    },
    ...mapGetters{[
      'hotList'
    ]}
  }
}
</script>
<style>
  ·······
</style>

在上面的例子中,我们在组件挂载完成之后发起了一个fetchList的action,并添加了一个名为request的参数,这里给一个week值,也可以给按照业务需要给month、year之类的值,接下来对aAction.js做一些修改。

actions/aAction.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'
import { toQueryString } from '../../utils'
import axios from 'axios'

export const fetchListAction = {
  fetchList ({ commit, state }, param) {
    commit(FETCH_LIST_REQUEST, {
      request: param['request']
    })
    axios.get(`http://youdomain.com/${param['request']}list`)
     .then(function (response) {
      commit(FETCH_LIST_SUCCESS, {
        request: param['request']
        data: response.data
      })
      console.log(response);
     })
     .catch(function (error) {
      commit(FETCH_LIST_FAILURE, {
        request: param['request']
        error: error
      })
      console.log(error);
     });
  }
}

请求成功之后,在 commit()中加入了一个request的参数,这样Mutation就可以从里面获取相应的参数,最后对aMutation做一些修改。

mutations/aMutation.js

import { FETCH_LIST_REQUEST, FETCH_LIST_SUCCESS, FETCH_LISR_FAILURE } from '../constants/types'

export const fetchListMutation = {
  [FETCH_LIST_REQUEST] (state, action) {
    state[action.request].isFetching = true
  },
  [FETCH_LIST_SUCCESS] (state, action) {
    state[action.request].isFetching = false
    state[action.request].data = action.data
    state[action.request].lastUpdated = (new Date()).getTime()
  },
  [FETCH_LIST_FAILURE] (state, action) {
    state[action.request].isFetching = false
    state[action.request].error = action.error
  }
}

state加入了[action.request],以区分不同的接口数据。

完成以上修改后,只需要在组件调用相应的action时加入不同的参数,就可以调用相同类型但数据不同的接口。

总结

以上是我在Vuex实践中总结的一些东西,分享给大家,如果有不合理或者错误❌的地方,也希望各位老司机不吝赐教,有机会多交流。也希望大家多多支持我们。

微信号:pasturn
Github:https://github.com/pasturn

(0)

相关推荐

  • 详解vuex之store源码简单解析

    关于vuex的基础部分学习于https://www.jb51.net/article/163008.htm 使用Vuex的时候,通常会实例化Store类,然后传入一个对象,包括我们定义好的actions.getters.mutations.state等.store的构造函数: export class Store { constructor (options = {}) { // 若window内不存在vue,则重新定义Vue if (!Vue && typeof window !== '

  • 详解vuex之store拆分即多模块状态管理(modules)篇

    了解vuex的朋友都知道它是vue用来集中管理状态的容器,如果了解过Reduce的朋友可能看见他时就会非常熟悉,都是用来管理全局的状态的,实现不同组件之间相互的数据访问.这里我们不介绍vuex,主要介绍vuex拆分store以及多模块管理.我们知道如果一个项目非常大的话状态就会非常的多,如果不进行分类处理,所有的状态都维护在一个state里面的话,状态管理就会变得非常的混乱,这样非常不利于项目的后期维护.我们现在前端推崇模块化开发,为的就是提高开发效率和维护效率,避免重复工作.那么vuex是怎么

  • vuex 解决报错this.$store.commit is not a function的方法

    Vue的项目中,如果项目简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式 进行传递 但是如果是大中型项目中,很多时候都需要在不相关的平行组件之间传递数据,并且很多数据需要多个组件循环使用.这时候再使用上面的方法会让项目代码变得冗长,并且不利于组件的复用,提高了耦合度. Vue 的状态管理工具 Vuex 完美的解决了这个问题. 看了下vuex的官网,觉得不是很好理解,有的时候我们只是需要动态的从一个组件中获取数据(官网称为"组件层级":是个独立的控件,作用范围

  • Vuex之理解Store的用法

    1.什么是Store? 上一篇文章说了,Vuex就是提供一个仓库,Store仓库里面放了很多对象.其中state就是数据源存放地,对应于与一般Vue对象里面的data(后面讲到的actions和mutations对应于methods). 在使用Vuex的时候通常会创建Store实例new Vuex.store({state,getters,mutations,actions})有很多子模块的时候还会使用到modules. 总结,Store类就是存储数据和管理数据方法的仓库,实现方式是将数据和方法

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

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

  • 详解vuex的简单使用

    1 目录的配置 根据官方推荐在src目录里面创建store目录 2 创建store里面的文件 根据官方推荐创建 actions.js, getters.js,index.js, mutations.js, mutations-types.js, state.js 2.1 state.js state.js: 是vuex的单一状态数,用一个对象就包含了全部的应用层级状态.至此它便作为一个『唯一数据源(SSOT)』而存在.这也意味着,每个应用将仅仅包含一个 store 实例.单一状态树让我们能够直接

  • 详解vuex中mapState,mapGetters,mapMutations,mapActions的作用

    在开始接触vuex框架的时候对那些state,action,mutation,getter等理解的还挺顺利的,然后突然出来一种加了一个前缀的mapState等,这样的就有点蒙圈了...特别是官方的文档并没有给除详细的说明跟例子...然后就自己慢慢理解了一下.其实也就是一个重命名而已...以下就是例子,希望能帮助理解: 在store中代码 import Vuex from 'vuex' import Vue from 'vue' Vue.use(Vuex); const store = new V

  • 详解JDK9特性之JPMS模块化

    简介 在module中会有元数据来描述该模块的信息和该模块与其他模块之间的关系.这些模块组合起来,构成了最后的运行程序. 听起来是不是和gradle或者maven中的模块很像? 通过组件化,我们可以根据功能来区分具体的模块,从而保持模块内的高聚合,模块之间的低耦合. 另外,我们可以通过模块化来隐藏接口的具体实现内容,从而不影响模块之间的调用. 最后,我们可以通过显示声明来描述模块之间的依赖关系.从而让开发者更好的理解系统的应用逻辑. JDK9中模块的实现 在JDK9之前,java是通过不同的pa

  • 详解Vuex中getters的使用教程

    目录 简介 说明 官网 getters概述 说明 来源 用法 示例 测试 简介 说明 本文用示例介绍Vuex的五大核心之一:getters. 官网 Getter | Vuex API 参考 | Vuex getters概述 说明 getters 是Store的计算属性,可以对State进行计算操作.就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算. 虽然组件内也可以做计算属性,但getters 可以在多组件之间复用.如果一个状态只在一个

  • 详解Linux 下开发微信小程序安装开发工具

    详解Linux 下开发微信小程序安装开发工具 1. git clone https://github.com/yuan1994/wechat_web_devtools 然后创建一个文件夹 mkdir /opt/tencent/ 移动文件 mv ./wechat_web_devtools /opt/tencent 修改用户组 chown -R root:root /opt/tencent/wechat_web_devtools 启动测试工具 /opt/tencent/wechat_web_devt

  • 详解 IOS下int long longlong的取值范围

    详解 IOS下int long longlong的取值范围 32bit下: unsigned int 0-4294967295 int -2147483648-2147483647 unsigned long 和int一样 long 和int一样 long long的最大值:9223372036854775807 long long的最小值:-9223372036854775808 unsigned long long的最大值:1844674407370955161 __int64的最大值:92

  • 详解Linux下读取位图的注意事项

    详解Linux下读取位图的注意事项 在Linux下读取位图遇到的问题,很好地体现了linux与Windows操作系统的不同.按理说位图格式与操作系统无关,读取也应该无关,实际上在位图读到内存中时已经不同.下面主要介绍自己在Linux下操作位图遇到的问题. (一).位图结构 位图一开始是两个结构体,包括位图的详细信息,是读取后面数据的关键.所以读取位图首先要正确读取这两个结构体:BITMAPFILEHEADER和BITMAPINFOHEADER.其具体定义为: typedef struct tag

随机推荐