咱們是否是真的須要狀態管理,答案是肯定的,計算你的項目達到了10W行代碼,那也並不意味着你必須使用它,應該由業務場景決定。引用Redux的做者Dan Abramov的話說就是: Flux架構就像眼鏡,您自會知道何時須要它。Vuex如是也。
目前Vuex在網上爭議並不大,用的好的人大有人在,不愛用的人也會使用其餘解決方案來作。在《你可能不須要Vuex》一文中,已經對組件化通訊講的至關明確,也分析了Vuex做爲集中式狀態管理的好處。然而,大多數文章對具有落地性的Vuex使用場景並無作整理和總結,都是一句「根據應用場景」來收尾。我我的是特別傾向使用Vuex的,他將分散在各處的數據進行集中式統一管理,視圖層能夠無侵入的接受可預測數據,有效下降耦合,顆粒化的維護各個模塊。然而,在咱們的實際開發過程當中,仍然有一些開發者對Vuex存在質疑甚至恨之入骨,這很大一部分緣由是因爲我的的編程習慣和學習經驗所致,另外一方面也警示着架構須要考慮這些人的問題。javascript
在一開始推廣Vuex時,大部分開發人員學習完Vuex後都會向我反饋,說Vuex代碼很是的繁瑣且冗餘,明明能夠一行代碼解決的,如今代碼量和文件量都擴大了。這些開發人員大部分是經歷過JQuery時代的悍將,他們早已習慣這種簡單粗暴的開發方式,卻不多閱讀新的知識體系來讓本身的技術有所昇華。的確,最保守狀況下,處理一個組件的數據,咱們須要有一個對應的store
文件,裏面包含了state
、getter
、mutation
、action
四個屬性,state
定義可預測的數據,getter
提供自動計算的數據,mutation
用於單向改變屬性,action
用於發送異步請求,原來一步能夠到位的,如今要分紅了四步,代碼量增長了不說,分文件以後更帶來了管理上麻煩。html
Vuex經過定義state
提供組件可預測的數據,當數據是由服務端獲取的時候,交由action
來獲取便可。然而,一部分人認爲,對於列表頁面,若是也使用store
,僅僅只是展現數據,除了以前的代碼繁瑣冗餘以外,還會致使內存佔用的問題。由於頁面切換後,服務端獲取的數據並無被釋放,仍然存儲在state
中,即使從跳轉的頁面返回,仍然要從新從服務端獲取一次最新數據。前端
以上問題,要說是問題還真是個問題,前端架構中除了針對系統應用要有很好的戰略佈局,對人來講也要造成必要的約束和規範。針對這些,咱們從前端架構中,增長了對Vuex的擴展,並制定相應的規則來規範開發人員的使用。vue
官網中有針對Vuex的模塊化解決方案,這裏我就很少贅述了,但官網提供了切割的方式,卻沒有給出很好的切割的解決方案。在咱們的項目中,咱們將開發的文件夾按照業務進行了劃分,每一個業務模塊能夠獨立發佈,也能夠和其餘的模塊合併打包。項目的業務模塊文件夾以下:java
src - modules ## 模塊文件夾 - user ## 用戶管理模塊 - mock ## 數據模擬 - store ## 數據服務 - view ## 視圖 - org ## 組織管理模塊 - mock ## 數據模擬 - store ## 數據服務 - view ## 視圖 - store-loader.js ## store加載器
全部視圖的store模塊
是由store-loader.js
加載出來的,它既是狀態樹的根
,同時又是module state
的加載器,負責將分散在各個模塊的store
整合起來。所以,開發人員並不須要維護一個龐大的狀態樹,而只須要去維護本身的業務模塊所需的模塊數據便可。webpack
由於webpack工程讓js能夠提早預編譯,因此,咱們的架構中都是讓store
和router
分散在各個模塊中,編譯時整合起來,而且這種整合咱們是按需加載的。ios
咱們的系統中是具有權限管理的,對於某些用戶沒有該模塊的權限,那麼這些js文件是不該該加載進來的,雖然會參與編譯。在用戶登錄以後,根據用戶權限零時組裝store
和router
。一方面讓用戶資源最小化,一方面也提高了應用性能和安全性。web
咱們的動態加載使用的是store
的registerModule
方法,一樣的,對於一些特定路由的數據,在離開後可使用unregisterModule
註銷模塊,刪除數據,避免內存持續佔用的問題。vuex
看到以上這些模式,會有人有如下的疑問:shell
由於咱們的項目架構把router
混合在了view
中,把api/services
混合進了store
中。前面的混合我會講一個專題來解釋爲何要這麼作,後面的混合就是爲了一部分解決以前咱們提到的開發人員所遇到的痛點問題。咱們能夠來看以下案例:
import api from '@src/api/counter'; const store = { state: { count: 0 }, mutations: { setCount (state, count) { state.count = count; } }, actions: { loadCount ({commit}) { api.loadCount().then((count) = { commit('setCount', count); }) } } };
api
中經過axios
向服務端發起請求獲取數據:
// @src/api/counter.js import axios from 'axios'; export default { loadCount: () => axios.get('/api/counter') };
對於api/serives
,太薄了,僅僅只是對axios
進行了一個函數的包裹,而中間咱們沒有加入任何的邏輯,也不該該加入邏輯。這樣作一方面不便於管理,也沒辦法發揮api
的意義。因此,咱們將api
整合進了store
,對於僅僅用於展現的組件來講就更加便利了,不須要定義state
、mutation
,直接經過action
返回promise
,交由組件去使用。
通過以上的思路,咱們讓代碼儘量的內彙集中,同時又分散耦合,配合服務端將加載量下降,經過架構中的模塊讓代碼量也適當下降。當開發量變得巨大的時候,這種方式會下降不少度複雜度,讓開發變得高效順暢。