前言
Vuex是专门为Vue.js开发的状态管理模式,它采用集中式的管理存储应用的组件状态,并确保以一种可预测的方式发生改变,这里的可预测指的是显示的提交actions
改变state
的状态
- state 状态 数据
- mutations 更改状态的函数
- actions 异步操作
- getters 从state中派生出的新状态 类似计算属性
store:
Vuex的核心思想,上述概念的容器,包含着应用中需要共享的状态state
出现的原因
当遇到多个组件共享状态的时候,单向数据流的简洁性就会受到破坏
- 多个视图依赖同一个状态
- 多个不同的视图行为需要修改同一个状态
第一种情况:多层嵌套可以采用传递参数的方式进行解决,但是兄弟组件之间的传值无法解决
第二种情况:可以采用事件通信的方式,但是这种方式比较脆弱,通常导致代码难以维护
解决: 将组件共享的状态抽离到和应用同级别,以一个全局单例的模式管理,这样任何组件都可以访问或者更改组件了
Vuex VS 全局对象
- Vuex的存储状态是响应式的,当我们的组件从store中访问数据的话 如果store中的数据发生改变,那么组件中的数据也会发生改变
- 改变Vuex中数据的唯一变化是通过显示的提交mutation,这样可以方便的跟踪每个状态的变化
Vuex实现的原理
将全局的状态抽离到和应用同级别,实现数据响应式的核心还是在Vuex内部通过new Vue
实例,将state作为data的数据 利用Vue的响应式原理实现store数据响应式,而Vuex的getter也是利用了Vue内部的计算属性原理实现的。在严格模式下还可以通过监测state的变化是否来源于外部,从而确保改变state的唯一途径是显示的提交mutations
。
对于复杂庞大的状态管理,我们还可以将store
拆分成一个个module,这个module下面还可以继续拆分,从而形成一个状态管理树,每个module都有自己的state、getters、mutations、actions
。
在初始化store实例的时候我们通过递归遍历模块的方式完成每个模块的初始化过程。
mutations
首先将当前模块的mutaion安装到 store._mutations
上,当我们调用当前模块的mutation方法时,实际上执行的是handler.call(store, local.state, payload)
,这个函数的第一个参数就是当前模块的state。
const moduleA = {
nameSpace: true,
state: {count: 1},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
}
最终挂在完成之后Store实例上的参数变成:
_mutaions: {
increment: [f],
a/increment: [f],
b/increment: [f]
}
Actions
Action
的初始化安装过程和Mutations
类似,唯一不同的是handler.call
函数的第二个参数,在这里是一个对象,这个对象中包含dispatch、commit、getters、state、store.getters、store.state
所以我们平时在调用actions中定义的方法的时候可以解析里面的参数
actions: {
increment ({ commit }) {
commit('increment')
}
}
Dispatch
store.dispatch('increment')
actions
是通过dispatch方式触发的, dispatch是定义在store原型上的方法,第一个参数是我们要触发的
mutations`上的方法,第二个参数是我们传入的参数.它的主要实现逻辑是:
- 首先解析出我们传入的触发类型和参数
- 然后通过
this._actions[type]
获取当前模块上的actions函数数组 - 遍历他们执行获取到的每个handler,实际上最终执行的是我们定义的
action
函数 - 我们定义的action函数能拿到当前模块下的
commit
方法