Vue面試考點之狀態(tài)管理VueX

1、Vuex 簡介

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。

狀態(tài)自管理應(yīng)用包含以下幾個部分:

state,驅(qū)動應(yīng)用的數(shù)據(jù)源;

view,以聲明方式將state映射到視圖;

actions,響應(yīng)在view上的用戶輸入導(dǎo)致的狀態(tài)變化。

單向數(shù)據(jù)流

以上是一個表示“單向數(shù)據(jù)流”理念的簡單示意。但是,當(dāng)我們的應(yīng)用遇到多個組件共享狀態(tài)時,單向數(shù)據(jù)流的簡潔性很容易被破壞,存在如下的情況:

a、多個視圖依賴于同一狀態(tài)。傳參的方法對于多層嵌套的組件將會非常繁瑣,并且對于兄弟組件間的狀態(tài)傳遞無能為力。

b、來自不同視圖的行為需要變更同一狀態(tài)。經(jīng)常會采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通常會導(dǎo)致無法維護(hù)的代碼。

所以我們需要把組件的共享狀態(tài)抽取出來,以一個全局單例模式進(jìn)行管理。

2、Vuex 核心概念

1)State

Vuex 使用單一狀態(tài)樹,即一個對象就包含了全部的應(yīng)用層級狀態(tài)。它便作為一個“唯一數(shù)據(jù)源”而存在。Vuex 通過store選項,提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個子組件中。由于 Vuex 的狀態(tài)存儲是響應(yīng)式的,從 store 實例中讀取狀態(tài)也是實時的。

2)Getters

Vuex 允許我們在 store 中定義“getter”(可以認(rèn)為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計算。Getter 接受 state 作為其第一個參數(shù):

Getter 會暴露為store.getters對象,你可以以屬性的形式訪問這些值。

Getter 也可以接受其他 getter 作為第二個參數(shù):

通過 this.$store.getters.doneTodosCount 可以很容易地在任何組件中使用它。

3)Mutation

更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的事件類型 (type)和 一個回調(diào)函數(shù) (handler)。這個回調(diào)函數(shù)就是我們實際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù)。

不能直接調(diào)用一個 mutation handler。這個選項更像是事件注冊:“當(dāng)觸發(fā)一個類型為increment的 mutation 時,調(diào)用此函數(shù)”。要喚醒一個 mutation handler,你需要以相應(yīng)的 type 調(diào)用store.commit方法。

可以向store.commit傳入額外的參數(shù),即 mutation 的載荷(payload)。

在大多數(shù)情況下,載荷應(yīng)該是一個對象,這樣可以包含多個字段并且記錄的 mutation 會更易讀。

對象風(fēng)格的提交方式

當(dāng)使用對象風(fēng)格的提交方式,整個對象都作為載荷傳給 mutation 函數(shù),因此 handler 保持不變

Mutation 需遵守 Vue 的響應(yīng)規(guī)則

既然 Vuex 的 store 中的狀態(tài)是響應(yīng)式的,那么當(dāng)我們變更狀態(tài)時,監(jiān)視狀態(tài)的 Vue 組件也會自動更新。

這就要求我們必須遵守一些Vuex對應(yīng)的規(guī)則:

a、提前在store中初始化好所需的屬性.

b、當(dāng)給state中的對象添加新屬性時, 使用下面的方式:

方式一: 使用Vue.set(obj, 'newProp', 123)

方式二: 用新對象給舊對象重新賦值,可以利用對象展開運算符(...)。

一條重要的原則就是要記住mutation 必須是同步函數(shù)。調(diào)試工具devtool 中的 mutation 日志。每一條 mutation 被記錄,devtools 都需要捕捉到前一狀態(tài)和后一狀態(tài)的快照。如果mutation 中存在異步函數(shù)的回調(diào),mutation 觸發(fā)的時候,回調(diào)函數(shù)還沒有被調(diào)用,devtools 不知道什么時候回調(diào)函數(shù)實際上被調(diào)用——實質(zhì)上任何在回調(diào)函數(shù)中進(jìn)行的狀態(tài)的改變都是不可追蹤的。

當(dāng)你調(diào)用了兩個包含異步回調(diào)的 mutation 來改變狀態(tài),你怎么知道什么時候回調(diào)和哪個先回調(diào)呢?在 Vuex 中,mutation 都是同步事務(wù);為了處理異步操作,提出了Action。

4)Action

Action 類似于 mutation,不同在于:

a、Action 提交的是 mutation,而不是直接變更狀態(tài)。

b、Action 可以包含任意異步操作。

Action 函數(shù)接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調(diào)用context.commit提交一個 mutation,或者通過context.state和context.getters來獲取 state 和 getters。

Action 通過store.dispatch方法觸發(fā)。mutation 必須同步執(zhí)行,Action 就不受約束!我們可以在 action 內(nèi)部執(zhí)行異步操作。

Actions 支持同樣的載荷方式和對象方式進(jìn)行分發(fā):

在Action中, 我們可以將異步操作放在一個Promise中, 并且在成功或者失敗后, 調(diào)用對應(yīng)的resolve或reject。

5)Module

Module是模塊的意思,Vue使用單一狀態(tài)樹,那么也意味著很多狀態(tài)都會交給Vuex來管理.

當(dāng)應(yīng)用變得非常復(fù)雜時,store對象就有可能變得相當(dāng)臃腫,為了解決這個問題,Vuex允許我們將store分割成模塊(Module), 而每個模塊擁有自己的state、mutation、action、getters等。

對于模塊內(nèi)部的 mutation 和 getter,接收的第一個參數(shù)是模塊的局部狀態(tài)對象。

對于模塊內(nèi)部的 action,局部狀態(tài)通過context.state暴露出來,根節(jié)點狀態(tài)則為context.rootState。

如果getters中也需要使用全局的狀態(tài), 可以接受更多的參數(shù)。根節(jié)點狀態(tài)會作為第三個參數(shù)暴露出來。

actions和mutations的區(qū)別:

①action提交的是mutation,而不是直接變更狀態(tài)

②actions用于處理一些異步事件,而mutations一般用于處理同步事件

③通過store.dispatch觸發(fā)action,參數(shù)是vuex.store實例(因為modules需要獲取上下文) 通過store.commit觸發(fā)mutation,參數(shù)是state,payload

3、VueX 實現(xiàn)

實現(xiàn)一個插件:聲明Store類,掛載$store。Store具體實現(xiàn):

a、創(chuàng)建響應(yīng)式的state,保存mutations、actions和getters;

b、實現(xiàn)commit根據(jù)用戶傳入type執(zhí)行對應(yīng)mutation;

c、實現(xiàn)dispatch根據(jù)用戶傳入type執(zhí)行對應(yīng)action,同時傳遞上下文;

d、實現(xiàn)getters,按照getters定義對state做派生。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容