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

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