Vuex 入門指南

1.Vuex是什麼?

咱們仍是像以往同樣先看一看官方文檔對此的解讀(Vuex 是什麼? · GitBookphp

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。

是否是又遇到了不少看起來很高大上聽起來卻一臉懵逼的專業術語?別急別急,咱們慢慢來剖析一下這個Vuex到底是個啥東西,他能作些啥。html

2.Vuex到底用來作什麼?

用通俗一點的話來講,Vuex就是一個用於管理SPA項目(不知道SPA是什麼?請參考本專欄代碼之美 - 知乎專欄中的歷史文章)中狀態的開源產品。vue

接下來又引出了一個問題,什麼是狀態,爲何要用Vuex這個東西去管理它?java

3.什麼是狀態?爲何要去管理它?

狀態這個東西其實咱們生活中隨處可見。咱們頭頂上的燈就有兩種狀態,一種是開,一種是關。狀態說白了就是燈這個對象的的某個屬性的值。git

若是你對狀態和屬性這兩個概念仍是有所不瞭解,那麼我打一個其餘的比方吧。github

咱們平時是否有玩過王者榮耀或者英雄聯盟LOL之類的網遊?這些遊戲裏面每個英雄當前都有生命值,法力值,攻擊力,法術強度,護甲和魔抗等等,這些是這個英雄的屬性,也就是英雄這個對象當前的狀態。ajax

屬性分爲固定屬性和可變屬性,通常像LOL裏面大部分ADC英雄若是沒有特殊的被動或者其餘裝備的支持,那麼它的的攻擊距離都是固定的,這個就是固定屬性,這種固定屬性的狀態因爲正常狀況下都是不變的,因此咱們能夠直接寫死在代碼中(這種寫死在代碼中的變量的值稱爲硬編碼),可是像其餘的攻擊力法術強度等等都是隨裝備和等級變化,那麼這種屬性是可變屬性。vuex

這些屬性的狀態因爲會根據用戶的各類操做(好比說出裝備,打怪升級升級)變化。在傳統的Vue.js的組件化開發中,通常這些狀態都是分散在各個組件中,此時此刻若是兩個英雄互相打起來了,那麼就得分別去不一樣的組件中取狀態值,而後進行狀態值的修改,最後還要互相讀取對方的狀態值。若是他們自己是父子組件,那麼還能夠經過事件觸發或者Prop屬性來傳遞狀態,可是若是是不一樣的組件,因爲因爲Vue.js自己組件之間有做用域,它們沒法直接相互通訊,因此就須要一些東西例如Vuex去集中管理和追蹤它的變化。(若是你如今仍是不明白這一大段話,能夠好好回顧一下官方文檔中組件 - vue.js非父子組件通訊 這個部分的內容)npm

在遊戲中,這些狀態通常以變量的形式保存在內存中,可是因爲用戶玩遊戲的時候並非直接去使用內存管理工具查看他們在內存裏面的值,而是經過遊戲界面去看這些值,因此還須要像Vue.js這種MVVM框架將狀態同步到視圖中。這就是Vue.js和Vuex之間的關係了。json

4.什麼狀況下我應該使用 Vuex?

官方文檔(Vuex 是什麼? · GitBook)中說:

雖然 Vuex 能夠幫助咱們管理共享狀態,但也附帶了更多的概念和框架。這須要對短時間和長期效益進行權衡。

若是您不打算開發大型單頁應用,使用 Vuex 多是繁瑣冗餘的。確實是如此——若是您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 global event bus 就足夠您所需了。可是,若是您須要構建是一箇中大型單頁應用,您極可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成爲天然而然的選擇。引用 Redux 的做者 Dan Abramov 的話說就是:

Flux 架構就像眼鏡:您自會知道何時須要它。

他的意思其實就是若是開發的程序並非很龐大,一個頁面中的組件不是不少而且他們之間並不須要大量頻繁的互相讀寫操做,那麼就能夠直接使用傳統的Vue.js中的組件Prop或者事件觸發來修改狀態,或者用組件 - vue.js#非父子組件通訊 中介紹的new一個空的Vue對象實例,而且經過事件觸發等方式來跨組件通訊。

不然的話仍是建議使用Vuex。雖然Vuex自己須要有一段時間的學習成本,可是這個學習成本相對於你開發時期使用傳統非父子組件通訊機制遇到的各類坑來講仍是比較划算的。這個就看你本身的權衡了。

5.Vuex怎麼安裝和使用?

在前面講解Vue.js入門的時候,咱們用的是Vue-Cli這個腳手架工具來搭建的,因爲這個腳手架工具自己會幫咱們配置好npm的package.json文件,這個文件裏面包含了這個Vue.js項目中全部依賴的包。

可是默認狀況下這個腳手架工具沒有爲咱們將Vuex這個依賴包給包含進去,因此咱們得本身去「聲明」一下咱們這個Vue.js項目中須要依賴Vuex這個包。

咱們該怎麼「聲明」呢?如今有兩種辦法:

一種是直接修改package.json,這種方法看起來有點複雜,不少新手怕一不當心修改出錯,可能會致使整個package.json文件結構出錯,影響之後項目的依賴安裝。

還有一種方法比較安全,只須要一行命令:

npm install vuex --save

表示安裝vuex這個包,--save表示將這個依賴包與本項目的依賴關係寫入package.json中。

而後咱們僅僅安裝了這個依賴包是沒有用的,咱們還得在以前Vue-Cli爲咱們自動構建好的項目文件中的main.js主入口文件的開頭裏面加上兩行這樣的代碼:

import Vuex from 'vuex'
Vue.use(Vuex)

第一行是用ECMAScript6的import將vuex包導入進來(這個是否是和java中導入jar包以及php中導入命名空間很類似?)

第二行是Vue.js自己的插件注入語法(參考官方文檔插件 - vue.js),將插件注入Vue.js的目的是方便咱們在插件內部調用它。

6.官方文檔的五大核心概念是什麼?

打開官方文檔(Introduction · GitBook)能看到五大核心概念,他們都是啥?看了半天官方文檔我仍是對它們沒什麼瞭解,樓主能不能以通俗易懂的方式講解一下它們的做用?固然能夠啦!

首先先看一遍這個代碼,不須要你看懂它。

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

7.State(狀態)

官方文檔:State · GitBook

這個狀態就是前面所介紹的「狀態」值的存放處。

看第6節末尾的代碼中,狀態就是在state屬性中以鍵值對的形式聲明這個SPA中全部的狀態。上面的代碼中聲明瞭一個count狀態。

之因此要在這裏聲明全部狀態的緣由,一是讓代碼更加優雅,若是你接手你同事的項目的時候,可以一眼從Vuex的狀態聲明中看出這個應用中有哪些狀態,確定開發效率槓槓滴。二是若是在這裏聲明瞭狀態,那麼Vuex就可以追蹤到這個狀態的變化。那麼Vue.js中就能夠在視圖中對這個狀態作出響應。

讀取狀態固然也是直接讀取這個屬性裏面的各類子屬性了。

8.Getter(獲取器)

官方文檔:Getters · GitBook

這個獲取器和一些後端開發中模型層ORM中的獲取器實際上是差很少的功能。

好比說後端返回給咱們的是一個int類型的時間戳,咱們想把這個時間戳轉換成正常人類可讀的文本型時間表現形式(好比說2017年3月11日 12:43:31),那麼咱們就得在全部獲取該狀態的代碼中增長一個轉換函數。

但是如今有了狀態獲取器以後,咱們能夠統一將這個時間戳轉字符串的函數寫在獲取器裏面,要調用的時候就直接調用獲取器就行了。

還有一些其餘場景也可使用獲取器,好比說像錯誤碼這種東西通常都是一個數字碼對應一個文字形式的錯誤緣由,咱們也能夠經過獲取器來實現經過錯誤碼拉取錯誤緣由的功能。

使用獲取器的方法則是直接調用Vuex實例的getter下的各類函數便可。

9.Mutations(轉變)

官方文檔:Mutations · GitBook

這個Mutations其實國內目前也沒有比較好的翻譯,一般咱們都是直接稱Mutations。

咱們前面只講了能夠經過調用Vuex的實例的state屬性或者getter獲取器來讀取狀態。可是沒講到如何修改狀態。

官方文檔中已經講了須要先在Vuex實例的Mutations下編寫對應的修改函數來修改狀態。而且要修改的時候,要經過Vuex實例的commit方法來提交修改。也就是說任何對state狀態的修改操做都必須寫在Mutations中,而且還得用Vuex實例的commit來提交修改操做,而且因爲Mutations函數能夠傳入參數,因此commit同理也能夠傳入參數。

這個時候可能有一些同窗就會提問了,前面既然講到了讀取能夠直接訪問Vuex實例的state屬性,爲何修改卻不能直接去操做Vuex實例的state呢?官方文檔和其餘高手的回答是:

再次強調,咱們經過提交 mutation 的方式,而非直接改變 store.state.count,是由於咱們想要更明確地追蹤到狀態的變化。這個簡單的約定可以讓你的意圖更加明顯,這樣你在閱讀代碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓咱們有機會去實現一些能記錄每次狀態改變,保存狀態快照的調試工具。有了它,咱們甚至能夠實現如時間穿梭般的調試體驗。

至關於咱們經過一個Mutations函數能夠顯式的在代碼中告訴開發者,咱們這個SPA中究竟會對狀態進行哪些操做,操做方式是什麼。而且在後期咱們使用一些輔助開發工具,能夠保存狀態的快照,就像git或者svn同樣能夠回滾狀態。若是你仍是有點不明白,總之你就按照官方文檔說的去作吧,等開發一段時間以後會慢慢明白做者的良苦用心的,哈哈。

還有一個問題就是爲何狀態修改的提交必須經過Vuex實例的commit方法提交呢?爲何不能直接調用Mutations函數呢?除了上面官方文檔中提到的緣由,網上還有高手解釋了:由於Vue.js的狀態修改實際上是在內部有一個修改隊列,經過commit的方式提交修改能夠保證狀態的修改是有序的。

10.Actions(動做)

官方文檔:Actions · GitBook

前面提到了Mutations中能夠對狀態進行操做,可是忘記告訴各位同窗,Mutations中對狀態的操做只能是同步操做,不能是異步操做。

若是這個時候咱們有一個對狀態的修改操做是異步的怎麼辦呢?

首先看看什麼是異步操做?好比說ajax就能夠選擇是否發起異步請求,發起異步請求以後,咱們就須要在回調函數裏面進行請求結果的處理。關於JavaScript異步的知識你們能夠先使用各類搜索引擎自學一下。

如今回到actions上來,看看官方文檔(Actions · GitBook):

Action 相似於 mutation,不一樣在於:

  • Action 提交的是 mutation,而不是直接變動狀態。
  • Action 能夠包含任意異步操做。

其實異步的狀態修改本質上仍是經過幾個同步操做組合的,因此咱們仍是得先聲明好mutation同步操做方法,而後在actions中進行異步操做。若是咱們暫時手頭上沒有ajax接口用於異步請求,那麼咱們能夠像官方文檔同樣用setTimeout這種最簡單的測試方法來理解。

actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } 

前面講到了mutation是用commit來提交操做的,那麼actions是怎麼提交的呢?官方文檔中說了actions是使用Vuex實例的dispatch方法來提交(其實說分發會更加準確)的。

至於其餘更詳細的actions操做官方文檔講的仍是比較清楚的,沒有什麼比較複雜的概念,能夠參考官方文檔學習,這裏不作更多講解。

至於後面「組合actions」中提到的Promise對象以及 async / await 都是JavaScript中的一些特性,你們能夠利用搜索引擎進行更多瞭解。

11.Modules(模塊)

官方文檔:Modules · GitBook

若是你的SPA項目很是的龐大,那麼狀態可能自己還須要進行分模塊分類管理,這個時候就須要用到模塊了。官方文檔中已經給出了比較詳細的模塊操做代碼,這裏再也不作更多講解。

至於前面在將actions的時候,官方文檔中說actions方法在聲明的時候須要帶上一個context參數,緣由在這裏能夠獲得解答:

對於模塊內部的 action,context.state 是局部狀態,根節點的狀態是 context.rootState

12.嚴格模式

官方文檔:嚴格模式 · GitBook

在嚴格模式下,不管什麼時候發生了狀態變動且不是由 mutation 函數引發的,將會拋出錯誤。這能保證全部的狀態變動都能被調試工具跟蹤到。

前面提到了state的修改須要經過提交Mutations或者分發Actions,可是事實上我直接修改state能夠嗎?固然也是能夠的,可是在開發階段,爲了儘量防止開發者直接修改,就能夠經過嚴格模式來檢測這種錯誤的修改方式,而且拋出異常。

可是官方文檔後面也提到了:

不要在發佈環境下啓用嚴格模式!嚴格模式會深度監測狀態樹來檢測不合規的狀態變動——請確保在發佈環境下關閉嚴格模式,以免性能損失。

所以不要在生產環境下開啓嚴格模式致使性能損失。

結語:

Vuex綜合來看是一個很是適合在Vue.js中使用的狀態管理工具,固然相似的狀態管理工具也有不少,好比說React的Redux。

可是咱們爲了可以儘量保證項目穩定性以及學習曲線的平滑,推薦在Vue.js中使用Vuex

相關文章
相關標籤/搜索