Vuex 是什么?
Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
一个库、框架的出现肯定是为了解决某一种问题,Vuex 也不例外,它主要解决了以下两种:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
它是把组件的共享状态抽取出来,以一个全局单例模式来管理。原理图如下:
当然 Vuex 肯定也不是适用于所有的场景,因为它带来了一些它自己的概念:State、Getters、Mutations、Actions、Modules 。若你的项目够简单,建议还是不要用 Vuex。
源码分析:我们从 Vuex 的使用方法开始入手:
初始化:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
从根组件注入 store:
new Vue({ el: '#app', store: store, })
从上面可以看出是通过 Vue.use 来使用 Vuex 的那 Vue.use 是什么呢?作用主要是来使用 Vue 的插件的。源码如下:
export function initUse (Vue: GlobalAPI) { Vue.use = function (plugin: Function | Object) { const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) // 防止多次 use if (installedPlugins.indexOf(plugin) > -1) { return this } // additional parameters const args = toArray(arguments, 1) args.unshift(this) // 根据 plugin 类型的不同执行不同逻辑。1.对象的时候,则执行它身上的intall 方法,2. plugin 函数时则直接执行 if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args) } else if (typeof plugin === 'function') { plugin.apply(null, args) } installedPlugins.push(plugin) return this } }
那 Vuex 既然是通过 Vue.use 调用的,那 Vuex 是要满足调用条件的,看下源码( 2.4.0 版本):
let Vue; class Store{ ... } function install(_Vue){ // 这里也是防止多次调用 Vue.use if (Vue) { console.error( '[vuex] already installed. Vue.use(Vuex) should be called only once.' ) return } Vue = _Vue applyMixin(Vue) } export default { Store, install, version: '__VERSION__', mapState, mapMutations, mapGetters, mapActions }
源码中看出确实包括 install 方法,它里面很简单只是调用了 applyMixin 方法:
export default function (Vue) { const version = Number(Vue.version.split('.')[0]) if (version >= 2) { // Vue 2.x 使用 mixin 方法 把 vuexInit 混入到 beforeCreate 钩子中 Vue.mixin({ beforeCreate: vuexInit }) } else { ... } function vuexInit () { ... } }
从上看出 install 方法根据 Vue 版本不同把 vuexInit 混入到组件中,Vuex 的使用是把实例化的 store 以选项的形式放到 Vue 根组件中,那子组件是如何获得 store 的呢?那就要依靠 vuexInit 了:
function vuexInit () { const options = this.$options if (options.store) { // 注入到根组件 this.$store = typeof options.store === 'function' ? options.store() : options.store } else if (options.parent && options.parent.$store) { // 子组件 $store 引用父组件的 $store ,保证全部使用的是同一个 store 对象。 this.$store = options.parent.$store } }
主要区分了根组件和子组件是如何获取 store 对象的。
至此 Vuex 注入 Vue 组件就讲解完了,总结:关键点是利用 mixin 方法混入一个方法,然后方法内部根据 options.parent 来一层层引用父级 store 属性。