Vuex從使用到原理解析

1、Vuex是什麼

  Vuex是專門爲Vuejs應用程序設計的狀態管理工具。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。html

一、Vuex的構成

  由上圖,咱們能夠看出Vuex有如下幾個部分構成:

1)state

state是存儲的單一狀態,是存儲的基本數據。vue

2)Getters

getters是store的計算屬性,對state的加工,是派生出來的數據。就像computed計算屬性同樣,getter返回的值會根據它的依賴被緩存起來,且只有當它的依賴值發生改變纔會被從新計算。vuex

3)Mutations

mutations提交更改數據,使用store.commit方法更改state存儲的狀態。(mutations同步函數)緩存

4)Actions

actions像一個裝飾器,提交mutation,而不是直接變動狀態。(actions能夠包含任何異步操做)bash

5)Module

Module是store分割的模塊,每一個模塊擁有本身的state、getters、mutations、actions。app

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態
複製代碼

6)輔助函數

Vuex提供了mapState、MapGetters、MapActions、mapMutations等輔助函數給開發在vm中處理store。異步

二、Vuex的使用

import Vuex from 'vuex';
Vue.use(Vuex); // 1. vue的插件機制,安裝vuex
let store = new Vuex.Store({ // 2.實例化store,調用install方法
    state,
    getters,
    modules,
    mutations,
    actions,
    plugins
});
new Vue({ // 3.注入store, 掛載vue實例
    store,
    render: h=>h(app)
}).$mount('#app');
複製代碼

2、Vuex的設計思想

  Vuex的設計思想,借鑑了Flux、Redux,將數據存放到全局的store,再將store掛載到每一個vue實例組件中,利用Vue.js的細粒度數據響應機制來進行高效的狀態更新。ide

  看了Vuex設計思想,內心不免會有這樣的疑問:函數

  • vuex的store是如何掛載注入到組件中呢?
  • vuex的state和getters是如何映射到各個組件實例中響應式更新狀態呢?

3、Vuex的原理解析

  咱們來看下vuex的源碼,分析看看上面2個疑惑的問題:工具

疑問1:vuex的store是如何掛載注入到組件中呢?

一、在vue項目中先安裝vuex,核心代碼以下:

import Vuex from 'vuex';
Vue.use(vuex);// vue的插件機制
複製代碼

二、利用vue的插件機制,使用Vue.use(vuex)時,會調用vuex的install方法,裝載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)
}
複製代碼

三、applyMixin方法使用vue混入機制,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
    }
}
複製代碼

  分析源碼,咱們知道了vuex是利用vue的mixin混入機制,在beforeCreate鉤子前混入vuexInit方法,vuexInit方法實現了store注入vue組件實例,並註冊了vuex store的引用屬性$store。store注入過程以下圖所示:

疑問2:vuex的state和getters是如何映射到各個組件實例中響應式更新狀態呢?

store實現的源碼在src/store.js

一、咱們在源碼中找到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狀態是響應式,是藉助vue的data是響應式,將state存入vue實例組件的data中;Vuex的getters則是藉助vue的計算屬性computed實現數據實時監聽。
  computed計算屬性監聽data數據變動主要經歷如下幾個過程:

小結

  Vuex是經過全局注入store對象,來實現組件間的狀態共享。在大型複雜的項目中(多級組件嵌套),須要實現一個組件更改某個數據,多個組件自動獲取更改後的數據進行業務邏輯處理,這時候使用vuex比較合適。假如只是多個組件間傳遞數據,使用vuex未免有點大材小用,其實只用使用組件間經常使用的通訊方法便可。

Vue組件簡單經常使用的通訊方式有如下幾種: 一、父子通訊: 父向子傳值,經過props;子向父傳值經過events ($emit);父調用子方法經過ref;provide / inject。 二、兄弟通訊:bus 三、跨級嵌套通訊:bus;provide / inject等。

相關文章
相關標籤/搜索