本文在 GitHub上的連結
昨天被問了一個問題:
Vuex 的應用場景有什麼?什麼時候適合使用 Vuex,什麼時候不適合使用 Vuex?
在當時,我的答案是一般人會回答的內容:
- 涉及到非父子關係的元件,例如兄弟關係、祖孫關係,甚至更遠的關係;
- 他們之間如果有資料互動,那麼應該使用Vuex來實現;
- 如果頁面複雜度比較低的話,也可以考慮使用
global-event-bus
來實現; - 如果只是父子關係的元件資料互動,那麼應該考慮使用props進行單向傳遞;
- 如果涉及到子元件向父元件的資料傳遞,那麼應該考慮使用
$emit
和$on
;
講道理說,這個答案也不算錯,當時我也只能回想起這些。
但後來,我又想了想,其實還可以更有針對性一些。
例如,在以下場景裡,我們應當使用 Vuex:
1、元件會被銷燬
我們可以假設這樣一個場景:
- 假如有這樣一個元件,他是彈窗,有一些核取方塊和輸入框,使用者會選擇和填寫資訊;
- 然後這個彈窗會被關閉和開啟,由於業務需要,這個彈窗輸入的內容,希望關閉後可以保留,在重新開啟後,內容依然存在。
解決辦法:
- 我們可以考慮將值存在父元件中,也就是說,實際修改的是父元件的值;
- 存在比如
sessionStorage
、cookies
之類的裡面,在created
時從中讀取,destroyed
的時候寫入其中; - 可以存到
global-event-bus
裡面;
但事實上,最好的還是存在 Vuex 裡:
- 可以直接通過
$store.state
來呼叫,通過commit()
來修改值; - 也可以在
created
的時候,讀取存在 state 裡面的值,在destroyed
的時候,寫回 state;
這樣處理的優點是解耦,不跟其他元件打交道。
2、元件基於資料而建立
我們可以假設這樣一個場景:
- 使用者登入後,讀取許可權配置表,這顯然是一個非同步操作;
- 這個配置表可能會影響很多頁面。比如被影響的元件的載入條件,例如是
v-if="$store.state.userInfo.superVIP
;
那麼:
- 因為讀取許可權配置表這個非同步操作,可能影響多個元件,而這些元件之間的關係,顯然是不可預料的(即不一定是在同一個父元件下面);
- 那麼這個非同步操作,寫在某一個元件裡就不太合適(因為其他元件讀取這個元件很不方便,即使他是根元件);
解決辦法:
- 一個妥協的解決辦法,是寫在
global-event-bus
裡面來實現; - 但是顯然,更好的解決辦法是寫在 vuex 裡面更專業一些;
3、多對多事件——多處觸發,影響多處
我們可以假設這樣一個場景:
- 假如有一個事件,比如:切換頁面顯示風格,他將改變某一個變數的值;
- 當該變數為
true
時,那麼頁面風格為白天(主要影響v-bind:style
的值); - 當該變數為
false
時,那麼頁面風格為晚上(同上); - 在多個地方可以切換這個頁面風格開關;
- 毫無疑問,這個變數將影響多個地方的
v-bind:style
的值; - 這就是 多對多 場景;
那麼:
- 無論這個變數放在哪個元件裡,其他元件呼叫他都是很麻煩的事情;
- 即使存於根元件,然後通過
this.$root.xx
來獲取這個變數,也是很麻煩的,而且很醜陋;
解決辦法:
- 如果不使用 Vuex,那麼我們可能會去考慮使用
global-event-bus
來儲存這個變數,並使用它; - 這不是不可以,但不優雅,而且管理麻煩;
- 而使用 Vuex,那麼這就是一件很方便的事情了;
- 我們可以通過
$store.state.xxx
來獲取這個變數的值; - 通過
$store.getters.yyy
來獲取某些基於這個值的,表示通用樣式(例如黑底白字)的物件; - 通過
$store.commit()
來提交修改(比如在某些情況下可以禁止修改); - 甚至可以通過
$store.dispatch()
來獲取其他風格的樣式,並通過$store.state
和$store.getters
來返回新風格的樣式;
4、總結
總而言之,假如你需要 資料 和 元件 分離,分別處理,那麼使用 Vuex 是非常合適的。
相反,如果不需要分離處理,那麼不使用 Vuex 也沒關係。
比如某個資料只跟某元件打交道,是強耦合的。那麼這個資料就應該存放在該元件的 data 屬性中。