vuex 2 入門與提高

langyahappy發表於2017-12-04

從計數器開始

讓我們從一個簡單的計數器,開始進入Vuex 的世界:

vuex 計數器 匯智網

計數器應用的資料模型很簡單:使用一個counter屬性來表示計數器的 當前值就夠了。

Vue例項的created鉤子 中,應用啟動了一個定時器,用來週期性地 遞增counter屬性的值 —— 由於counter是響應式屬性,它的變化因而 驅動了檢視隨之重新整理。

可以說counter抽象地表達了計數器檢視的本質特徵,當counter的 值確定時,我們可以確定地推理出檢視的表現。像counter這樣可以決定 檢視表現的資料,在Vuex中就被稱為狀態

計數器應用相當簡單,因此我們只需要定義一個狀態就可以了。稍微複雜 一些的應用,則可能需要我們抽象出成百上千的狀態,這時候就需要分類 管理了。

例如,對於一個電商應用,我們將其購物車相關的狀態歸入cart類:

vuex 購物車 匯智網

你看到,應用的全部狀態,構成了一棵層級分明的狀態樹。而Vuex的作用 ,就在於管理一個應用的狀態樹。

應用單一狀態樹

Vuex進行應用狀態管理 的第一個手段,是要求應用建立並維護一個單一的、全 應用範圍共享的狀態樹,而不是各個元件單獨維護自己的狀態(在元件中使用data配置項宣告) —— 不過這不是絕對的,那些完全不需要在多個元件間 共享的狀態,依然可以在元件內部宣告。

出於學習的目的,同時為了避免引入複雜的演示程式碼,我們假設計數器的counter狀態需要與其他元件共享,因此我們將其定義遷移到狀態樹中。

建立狀態庫

Vuex的Store類 —— 狀態庫 —— 用於管理狀態樹,它的例項化配置項state用來宣告要建立的狀態樹。例如,下面的程式碼建立了一個包含狀態counter的 狀態庫:

conststore =newVuex.Store(

{

            state:{ counter:0}

       }

)

利用狀態庫的state屬性,就可以訪問到其管理的狀態樹了。例如,通過store.state.counter來訪問counter狀態。

需要指出的是,狀態庫的state屬性 —— 狀態樹 —— 是一個響應式屬性,因此 我們可以使用狀態樹上的這些狀態來驅動檢視的自動更新。

使用計算屬性訪問狀態樹

在建立了全應用單一狀態樹之後,接下來我們要考慮的就是在元件中怎麼使用 樹上的狀態了 —— 我們已經決定不宣告元件的私有狀態。

最簡單的方法是將樹上的狀態,對映為元件的計算屬性。例如,下面的程式碼將 狀態樹上的counter狀態,對映為元件的可讀寫計算屬性:

constEzCounter = { 

    template:'{ {counter} }',  

    computed:{    

        counter:{

            get() {returnstore.state.counter },

            set(v){ store.state.counter = v }    

        }

    }

}

將狀態庫注入元件

另一種方法是將狀態庫掛接為Vue例項的一個屬性上,這樣我們就可以在模板中 直接訪問狀態樹了(模板的上下文物件是所屬的Vue例項)。

在建立Vue例項時,使用store配置項,就可以將狀態庫掛接為Vue例項 的屬性$store,而且這個Vue例項的所有後代例項,也都有$store指向 同一個狀態庫,看起來就像是將狀態庫注入了元件樹上的每一個例項。

例如,下面的程式碼使用store配置項,將狀態庫store注入根元件,因此 我們可以在EzCounter元件中利用$store屬性訪問狀態庫:

const EzCounter = { 

    template:'{{$store.state.counter}}'

}

new Vue({  
      store:store,  

      template:'',  

      components:{EzCounter}

})

狀態變更管理

Vuex進行狀態管理 的第二個手段,是承擔起管理狀態變更(mutation)的 責任。

Vuex要求元件將狀態樹視為只讀,元件不應該直接修改狀態樹上的狀態, 而是通過提申請的方式,由狀態庫來實際執行狀態變更的操作:

vuex 狀態 匯智網

對於計數器應用來講,修改counter狀態的需求有兩個:遞增和復位。 因此,我們需要首先在狀態庫中宣告兩個變更處理器(mutation handler)。

在建立狀態庫時,使用mutations配置項來宣告變更處理器。例如,下面 的程式碼為狀態庫宣告瞭兩個變更處理器:INCREASE和RESET:

conststore =newVuex.Store({

        state:{counter:0},

        mutations:{
                          INCREASE:state=>state.counter++ ,
                          RESET:state=>state.counter =0
                        }
})

Vuex推薦使用大寫字母來命名變更處理器,因為這個名字也將作為 元件提交的變更請求的型別名 —— 從元件的角度看,還有比大寫的名字 更能表達出這是一個請求而不是實際操作嗎 —— 回憶一下Windows 的WM_系列訊息的名字。

狀態變更處理器(mutation handler)的引數是一個區域性上下文 (local context)物件的state屬性,我們需要利用這個引數來 更新狀態樹上指定的狀態。區域性上下文是Vuex為實現狀態樹的模組化管 理而構造的狀態庫區域性映象,我們將在《模組化管理》章節詳細講解 區域性上下文(local context)物件。現在,就把它暫時理解為原始的 狀態庫好了。

提交變更請求

元件應當呼叫狀態庫的commit()方法來提交指定型別的狀態變更請求。 例如,下面的程式碼向狀態庫提交了遞增counter狀態的申請:

store.commit('INCREASE')

狀態變更的同步性

Vuex進行狀態管理 的第三個手段,是要求應用保證狀態變更(mutation)的 同步性 —— 狀態變更處理器執行完之時,狀態更新一定要完成。

這意味著,在狀態變更處理器裡不能執行非同步程式碼。這一要求直接導致了新的 環節的引入 —— 狀態動作(action):

image

根據作者的說法(原文參見:About mutations usefulness), 引入狀態動作(action)這一環節的唯一目的,就是為了保證狀態變更(mutation) 的同步性:"Actions vs. mutations is all about separating asynchronicity from actual mutations"

狀態動作(action)隔離了元件和狀態庫,元件現在應當分發執行狀態庫宣告的動作, 然後由狀態動作負責提交變更請求。

在建立狀態庫時,使用actions配置項宣告狀態動作。例如,下面的程式碼 宣告瞭兩個狀態動作inc和reset,分別用來提交INCREASE和RESET變更 請求:

conststore =newVuex.Store({

    state:{counter:0},

    mutations:{INCREASE:state=>state.counter++,RESET:state=>state.counter =0},

    actions:{inc:context=>context.commit('INCREASE'),

    reset:context=>context.commit('RESET')  }

})

狀態動作(action handler)的引數是一個區域性上下文(local context)物件, 我們已經知道它是Vuex為模組構造的狀態庫區域性映象,因此呼叫它的commit()方法, 就可以提交變更請求了。

分發執行狀態動作

呼叫狀態庫的dispatch()方法來分發執行指定名稱的狀態動作。例如, 下面的程式碼要求狀態庫執行inc動作:

store.dispatch('inc')

更多關於vuex的精彩內容請到這裡來:

最新的 Vuex 2 入門與提高教程

相關文章