vuex源码
源码分析
简单示例
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
1. Vuex的注册
Vue官方建议的插件使用方法是使用Vue.use方法,这个方法会调用插件的install方法,看看install方法都做了些什么,从index.js中可以看到install方法在store.js中抛出,部分代码如下
let Vue // bind on install
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
声明了一个Vue变量,这个变量在install方法中会被赋值,这样可以给当前作用域提供Vue,这样做的好处是不需要额外import Vue from 'vue' 不过我们也可以这样写,然后让打包工具不要将其打包,而是指向开发者所提供的Vue,比如webpack的externals,这里就不展开了。执行install会先判断Vue是否已经被赋值,避免二次安装。然后调用applyMixin方法,代码如下
// applyMixin
export default function (Vue) {
const version = Number(Vue.version.split('.')[0])
if (version >= 2) {
Vue.mixin({ beforeCreate: vuexInit })
} else {
// override init and inject vuex init procedure
// for 1.x backwards compatibility.
const _init = Vue.prototype._init
Vue.prototype._init = function (options = {}) {
options.init = options.init
? [vuexInit].concat(options.init)
: vuexInit
_init.call(this, options)
}
}
/**
* Vuex init hook, injected into each instances init hooks list.
*/
function vuexInit () {
const options = this.$options
// store injection
// 当我们在执行new Vue的时候,需要提供store字段
if (options.store) {
// 如果是root,将store绑到this.$store
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
// 否则拿parent上的$store
// 从而实现所有组件共用一个store实例
this.$store = options.parent.$store
}
}
}
这里会区分vue的版本,2.x和1.x的钩子是不一样的,如果是2.x使用beforeCreate,1.x即使用_init。当我们在执行new Vue启动一个Vue应用程序时,需要给上store字段,根组件从这里拿到store,子组件从父组件拿到,这样一层一层传递下去,实现所有组件都有store访问到store
接下去继续看例子
// store.js
export default new Vuex.Store({
state: {
count: 0
},
getters: {
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
},
actions: {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement')
},
mutations: {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}
})