Vuex 的應用場景

qq20004604發表於2017-12-25

本文在 GitHub上的連結

昨天被問了一個問題:

Vuex 的應用場景有什麼?什麼時候適合使用 Vuex,什麼時候不適合使用 Vuex?

在當時,我的答案是一般人會回答的內容:

  1. 涉及到非父子關係的元件,例如兄弟關係、祖孫關係,甚至更遠的關係;
  2. 他們之間如果有資料互動,那麼應該使用Vuex來實現;
  3. 如果頁面複雜度比較低的話,也可以考慮使用 global-event-bus 來實現;
  4. 如果只是父子關係的元件資料互動,那麼應該考慮使用props進行單向傳遞;
  5. 如果涉及到子元件向父元件的資料傳遞,那麼應該考慮使用 $emit$on

講道理說,這個答案也不算錯,當時我也只能回想起這些。

但後來,我又想了想,其實還可以更有針對性一些。

例如,在以下場景裡,我們應當使用 Vuex:

1、元件會被銷燬

我們可以假設這樣一個場景:

  1. 假如有這樣一個元件,他是彈窗,有一些核取方塊和輸入框,使用者會選擇和填寫資訊;
  2. 然後這個彈窗會被關閉和開啟,由於業務需要,這個彈窗輸入的內容,希望關閉後可以保留,在重新開啟後,內容依然存在。

解決辦法:

  1. 我們可以考慮將值存在父元件中,也就是說,實際修改的是父元件的值;
  2. 存在比如 sessionStoragecookies之類的裡面,在 created 時從中讀取,destroyed的時候寫入其中;
  3. 可以存到 global-event-bus 裡面;

但事實上,最好的還是存在 Vuex 裡:

  1. 可以直接通過 $store.state 來呼叫,通過 commit() 來修改值;
  2. 也可以在 created 的時候,讀取存在 state 裡面的值,在 destroyed 的時候,寫回 state;

這樣處理的優點是解耦,不跟其他元件打交道。

2、元件基於資料而建立

我們可以假設這樣一個場景:

  1. 使用者登入後,讀取許可權配置表,這顯然是一個非同步操作;
  2. 這個配置表可能會影響很多頁面。比如被影響的元件的載入條件,例如是 v-if="$store.state.userInfo.superVIP

那麼:

  1. 因為讀取許可權配置表這個非同步操作,可能影響多個元件,而這些元件之間的關係,顯然是不可預料的(即不一定是在同一個父元件下面);
  2. 那麼這個非同步操作,寫在某一個元件裡就不太合適(因為其他元件讀取這個元件很不方便,即使他是根元件);

解決辦法:

  1. 一個妥協的解決辦法,是寫在 global-event-bus 裡面來實現;
  2. 但是顯然,更好的解決辦法是寫在 vuex 裡面更專業一些;

3、多對多事件——多處觸發,影響多處

我們可以假設這樣一個場景:

  1. 假如有一個事件,比如:切換頁面顯示風格,他將改變某一個變數的值;
  2. 當該變數為 true 時,那麼頁面風格為白天(主要影響 v-bind:style 的值);
  3. 當該變數為 false 時,那麼頁面風格為晚上(同上);
  4. 在多個地方可以切換這個頁面風格開關;
  5. 毫無疑問,這個變數將影響多個地方的 v-bind:style 的值;
  6. 這就是 多對多 場景;

那麼:

  1. 無論這個變數放在哪個元件裡,其他元件呼叫他都是很麻煩的事情;
  2. 即使存於根元件,然後通過 this.$root.xx 來獲取這個變數,也是很麻煩的,而且很醜陋;

解決辦法:

  1. 如果不使用 Vuex,那麼我們可能會去考慮使用 global-event-bus 來儲存這個變數,並使用它;
  2. 這不是不可以,但不優雅,而且管理麻煩;
  3. 而使用 Vuex,那麼這就是一件很方便的事情了;
  4. 我們可以通過 $store.state.xxx 來獲取這個變數的值;
  5. 通過 $store.getters.yyy 來獲取某些基於這個值的,表示通用樣式(例如黑底白字)的物件;
  6. 通過 $store.commit() 來提交修改(比如在某些情況下可以禁止修改);
  7. 甚至可以通過 $store.dispatch() 來獲取其他風格的樣式,並通過 $store.state$store.getters 來返回新風格的樣式;

4、總結

總而言之,假如你需要 資料元件 分離,分別處理,那麼使用 Vuex 是非常合適的。

相反,如果不需要分離處理,那麼不使用 Vuex 也沒關係。

比如某個資料只跟某元件打交道,是強耦合的。那麼這個資料就應該存放在該元件的 data 屬性中。

相關文章