一、Vuex是什么
Vuex是專門為Vuejs應用程序設計的狀態管理工具。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
1、Vuex的構成
由上圖,我們可以看出Vuex有以下幾個部分構成:
1)state
state是存儲的單一狀態,是存儲的基本數據。
2)Getters
getters是store的計算屬性,對state的加工,是派生出來的數據。就像computed計算屬性一樣,getter返回的值會根據它的依賴被緩存起來,且只有當它的依賴值發生改變才會被重新計算。
3)Mutations
mutations提交更改數據,使用store.commit方法更改state存儲的狀態。(mutations同步函數)
4)Actions
actions像一個裝飾器,提交mutation,而不是直接變更狀態。(actions可以包含任何異步操作)
5)Module
Module是store分割的模塊,每個模塊擁有自己的state、getters、mutations、actions。
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。
2、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');
二、Vuex的設計思想
Vuex的設計思想,借鑒了Flux、Redux,將數據存放到全局的store,再將store掛載到每個vue實例組件中,利用Vue.js的細粒度數據響應機制來進行高效的狀態更新。
看了Vuex設計思想,心里難免會有這樣的疑問:
- vuex的store是如何掛載注入到組件中呢?
- vuex的state和getters是如何映射到各個組件實例中響應式更新狀態呢?
三、Vuex的原理解析
我們來看下vuex的源碼,分析看看上面2個疑惑的問題:
疑問1:vuex的store是如何掛載注入到組件中呢?
1、在vue項目中先安裝vuex,核心代碼如下:
import Vuex from 'vuex'; Vue.use(vuex);// vue的插件機制
2、利用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) }
3、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
1、我們在源碼中找到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組件簡單常用的通信方式有以下幾種:
1、父子通信:
父向子傳值,通過props;子向父傳值通過events ($emit);父調用子方法通過ref;provide / inject。
2、兄弟通信:bus
3、跨級嵌套通信:bus;provide / inject等。