vuex源码分析

什么是vuex

在这里插入图片描述
先来看官方介绍:

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能

vuex是mcv模式中的model层,数据通过 state->components->acticon->mutation,然后改变状态,在结合双向绑定实现页面更新

vue和vuex

先看代码

new Vuex.Store({
    state:{},
    mutations:{},
    actions:{},
    getters:{}
})
new Vue({
    data:{},
    methods:{},
    computed:{}
})

可以看出vue和vuex差不多,

  • state->data
  • 获取数据 getters->computed
  • 更改数据 mutations-> methods

通过修改mutations方法修改state数据。
说到mutations和actions不得不说commit和dispatch,通过点击事件触发methods的方法,当存在异步时,vuex通过dispatch方法触发actions中的commit来使用mutations中的方法

vuex源码分析

vuex借鉴了flux和redux等,把数据存放在全局的store中,再将store挂载到vue的组件实例中

vuex的store挂载
  1. 在vue中安装vuex
import Vuex from 'vuex';
Vue.use(vuex);// vue的插件机制
  1. 在vue.use(vuex)时,调用vuex的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)
}
  1. applyMixin方法,在vue生命周期beforeCreate钩子函数前混入vuexInit方法
Vue.mixin({ beforeCreate: vuexInit });

function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
}

这步使用vue的mixin混入,实现store注入vue组件实例,注册vuex的store属性($store)

vuex中state和getters如何映射组件中更新
  1. vuex源码中resetStoreVM方法
function resetStoreVM (store, state, hot) {
  const oldVm = store._vm

  // 设置 getters 属性
  store.getters = {}
  const wrappedGetters = store._wrappedGetters
  const computed = {}
  // 遍历 wrappedGetters 属性
  forEachValue(wrappedGetters, (fn, key) => {
    // 给 computed 对象添加属性
    computed[key] = partial(fn, store)
    // 重写 get 方法
    // store.getters.xx 其实是访问了store._vm[xx],其中添加 computed 属性
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key],
      enumerable: true // for local getters
    })
  })

  const silent = Vue.config.silent
  Vue.config.silent = true
  // 创建Vue实例来保存state,同时让state变成响应式
  // store._vm._data.$$state = store.state
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed
  })
  Vue.config.silent = silent

  // 只能通过commit方式更改状态
  if (store.strict) {
    enableStrictMode(store)
  }
}

可以看出vuex中state借用data,将state存入vue实例中的data,而vuex中的getters借用vue的computed实现数据监听

vuex中mutations如何更新

registerMutation方法中,获取store中mutation type函数集合,再将新的函数push进去,再通过原函数传入state。

// 注册对应模块的mutation,供state修改使用
module.forEachMutation((mutation, key) => {
  const namespacedType = namespace + key
  registerMutation(store, namespacedType, mutation, local)
})
 
// 注册对应模块的action,供数据操作、提交mutation等异步操作使用
module.forEachAction((action, key) => {
  const namespacedType = namespace + key
  registerAction(store, namespacedType, action, local)
})
 
// 注册对应模块的getters,供state读取使用
module.forEachGetter((getter, key) => {
  const namespacedType = namespace + key
  registerGetter(store, namespacedType, getter, local)
})
function registerMutation (store, type, handler, local) {
  // 取出对应type的mutations-handler集合
  const entry = store._mutations[type] || (store._mutations[type] = [])
  // commit实际调用的不是我们传入的handler,而是经过封装的
  entry.push(function wrappedMutationHandler (payload) {
    // 调用handler并将state传入
    handler(local.state, payload)
  })
}
为什么state只能在mutations中修改

如果不开启严格模式,state可以直接修改
如果使用actions中修改,vuex会给与警报,因为源码中action只能有一个声明,在多个action 中修改,可能会产生异步错误。而直接修改也属于dispatch异步修改,所以官方会给与警告

参考:http://www.imooc.com/article/291242

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章