vuex源码

154 阅读1分钟

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属性,这样我们就可以在任何组件中通过this.store属性,这样我们就可以在任何组件中通过this.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--
    }
  }
})