浅谈 VueX 状态管理模式

前言

我们知道Vue组件通讯基本的方式有 子传父,父传子,平行兄弟组件通信,那么在简单的应用当中,Vue Store这种单一状态管理基本的方式就可以满足我们的日常需求,但是若要遇到大型复杂系统,你比如说,我有个数据,需要在多个实例,多层实例之间来回传递共享,那么一层一层的接收与发送就显得非常繁琐,并且组件之间的状态管理会显得十分麻烦,那么这个时候我们就应该考虑应用VueX了。

什么是VueX

VueXvue状态管理开发模式,以可预测的方式发生变化,那么首先先解释下相关基本组成成分

1.事件组成

  • dispatch : 触发事件,是唯一能执行action的方法
  • commit :    状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
  • mutate :    状态改变过程
  • render :    编译过程

2.基本对象组成

  • state : 存储状态(变量)
  • getters : 可以理解为store 的计算属性,说的通俗一点就是我可以通过getters将state重新赋值,重新定义
  • mutations : 修改状态并且是同步的方法(唯一改变state的途径)
  • actions : 提交的是 mutation,而不是直接变更状态。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发,该模块提供了Promise的封装,以支持action的链式触发
  • modules : store的子模块,为了开发大型项目,方便模块化状态管理而使用的

*注:VueX不能直接更改状态,必须通过提交(commit) mutations

3.基本流程

1.Vue组件接收状态并且交互,调用dispatch()方法
2.dispatch()方法触发actions里的相关对应方法
3.actions里的相关对应方法如果需要改变state状态,则调用commit()方法
4.commit()方法提交mutation修改state
5.render的过程通过getters对应的计算属性获取到新的state状态
6.重新渲染Components,更新视图

*注:VueX一旦更改了state状态,与之相关的所有组件都会收到相应变化

浅谈 VueX 状态管理模式_第1张图片

4.接下来我将写一个基于模块化的Vuex状态管理的使用(这里就是使用ModuleStore分割),因为基于单一的状态管理,所有的状态操作都存放在一个对象里,会变得十分繁琐,同样对象会堆得越来越大,那么首先我们先看下基本的结构是什么样子

const store = new Vuex.Store({
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... },
  modules: {
    a: moduleA,
    b: moduleB
  }
})

5.首先,我通过一个Demo实例来解释VueX如何使用,结构如下

浅谈 VueX 状态管理模式_第2张图片
image.png

6.这里我做了全局和局部模块拆分的处理,全局store存放在global.js,模块化的以文件为单位,存放在modules文件夹下,最后通过index.js合并导出.同样我用两个子组件ChildAChildB,一个父组件Parents来说明组件之间如何实现全局控制。代码示例如下

  • global.js
/**
 * Created by Echonessy on 2019.09.29
 * 全局store 配置
 */

//components 执行dispatch('addAction')
// 触发actions的addAction方法
//  addAction通过commit('add')触发mutations的add方法改变state
//  getter计算后重新渲染到页面上

//golbal state
export const state = {
  golbalNumber:0
}
//golbal getters
export const getters = {
  golbalNumber: state => state.golbalNumber+'_golbalGetters',
}
//golbal mutations
export const mutations = {
  addGolbalMutation:state => {state.golbalNumber++;},
  subGolbalMutation:state => {state.golbalNumber--;},
}
//golbal actions
export const actions = {
  addGolbalAction ({ commit }) {
    commit('addGolbalMutation')
  },
  subGolbalAction ({ commit }) {
    commit('subGolbalMutation')
  },
}

export default {
  state,
  getters,
  mutations,
  actions
}

  • childa.js
/**
 * Created by Echonessy on 2019.09.29
 * childa 模块 配置
 */
export const state = {
  number:1
}

export const getters = {
  childNumber: state => state.number+'_fromChildA',
}

export const mutations = {
  addMutation:state => {
    state.number++;
  },
  subMutation:state =>{
    state.number--;
  }
}

export const actions  = {
  addAction ({ commit }) {
    commit('addMutation')
  },
  subAction({ commit }){
    commit('subMutation')
  }
}

export default {
  namespaced: true, //在使用模块化的时候,dispatch('childb/addAction')
  state,
  getters,
  mutations,
  actions
}

  • childb.js
/**
 * Created by Echonessy on 2019.09.29
 * childb 模块 配置
 */
export const state = {
  number:1
}

export const getters = {
  childNumber: state => state.number+'_fromChildB',
}

export const mutations = {
  addMutation:state => {
    state.number++;
  },
  subMutation:state =>{
    state.number--;
  }
}

export const actions  = {
  addAction ({ commit }) {
    commit('addMutation')
  },
  subAction({ commit }){
    commit('subMutation')
  }
}

export default {
  namespaced: true, //在使用模块化的时候,dispatch('childb/addAction')
  state,
  getters,
  mutations,
  actions
}

  • index.js 主入口
import Vue from 'vue'
import Vuex from 'vuex'
import global from './global'

Vue.use(Vuex)

const modulesFiles = require.context('./modules', true, /\.js$/);
// module 合并
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1');
  const value = modulesFiles(modulePath);
  modules[moduleName] = value.default
  return modules
}, {})

const obj = {}
obj.modules = modules;
const options = Object.assign(global,obj)
const store = new Vuex.Store(options)

export default store

7.main.js主入口文件引入

import Vue from 'vue'
import App from './App'
import router from './router'
import store from "./store";

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: ''
})

8.我们打印index.js里的options,结构如下,我们可以看到整个store的基本结构

浅谈 VueX 状态管理模式_第3张图片
image.png

9.上面已经讲了 VueX的运行流程,那么我们在组件内如何去修改 state? 我用一个 Parents组件就能够完全说明

  • parents.vue




10.基本效果


浅谈 VueX 状态管理模式_第4张图片

11.最后代码地址:demo

你可能感兴趣的:(浅谈 VueX 状态管理模式)