flux架構淺談:什麼資料才應該放store

vilien發表於2017-03-25

flux架構淺談:什麼資料才應該放store

相信很多用過react和vue等框架的人都有思考過這個問題。React的出現,隨之帶來了flux這一設計理念。從React的Reflux、Redux,再到vue的vuex,一路使用過來,我覺得是該總結一下的時候了。

flux的機制已經有太多文章寫過了,這裡就不再多說。如果還不瞭解的,可以參看阮一峰的Flux 架構入門教程。這裡簡單介紹一下目前主流的三種flux架構:

Reflux是我最早接觸的flux架構,它把flux的結構簡化了,帶來了一些便利,但卻做得不夠好。它的store並不唯一,並且允許你建立多個store。如果處理不好,維護起來也是夠嗆。

Redux在這方面就做得很棒,它的store只有一個,並且引入了immutable的概念,使得store的可預測性更進一步。但是它的非同步操作是痛點,雖然有如saga這種優秀的中介軟體,但對於新手來說,還是很容易繞暈。

vuex這方面做得挺不錯,它把非同步操作限定在了actions階段,減少了很多繁瑣步驟。它的store也是唯一,但你可以在任何地方用this.$store去引用,方便的同時,對習慣不好的同學,也會帶來一些隱患。

好了,接下來我們該進入主題了。

多方觀點

前兩天,和同事在store裡面應該存放何種資料的問題上產生了分歧,於是我查了不少資料,也跟一些技術大牛進行過探討。總結起來,目前主流的觀點有兩種:

  1. store只存放公共資料,元件的資料、狀態自行維護

  2. 所有資料都應走store,view層只管展現資料,這也是flux官方所推薦的做法

這裡特別強調一下,本文所探討的是SPA應用。所以,如無特殊說明,這裡指的元件,特指頁面級元件,或者說路由級元件,並非單元件。另外,flux官方並無資料的概念,所有資料均是狀態。那我為什麼要特意抽出來呢?後面會說。

持觀點1的人認為:只有公共的資料、需要跨元件的資料才應放入store。優點是store小,頁面元件內的資料不必繞來繞去,開發簡單。

持觀點2的人認為:呃,貌似我自己也差不多這種思想,為免帶入個人思想,這裡就不妄自猜度他人想法了。

store定位

目前各方都有一定的支援人數,那麼,要理清這個問題,我們就得先把store的角色定位好。是做為資料中心呢?還是做為全域性變數倉庫?或者還有另外的想法?

自從接觸flux以來,我也一直遵循第二種思路,但又不完全是。store是什麼?從字面上理解,就是一份儲存,一份放在本地的儲存。再來看一下我們目前的前後端互動,拉取 => 展現,再拉取 => 再展現。每切換一次頁面,都要再拉取一次資料。我們為什麼不能做到更好呢?把store定位為一份伺服器資料本地快照如何?沒錯,這就是我的思路。

傳統應用開發,我們的應用程式都是直接和資料庫互動的。但前端不行,拋開還需要後端程式提供介面不說,前端與資料庫中間還隔著http這層,這就產生了巨大的延時。所以,為什麼我們不能在本地建立一份資料快照?用store來做這事是不是合適?

也許你會說,localStorage、indexDB來做這事才更合適。localStorage大小且不說,你還需要藉助JSON來進行資料維護。而indexDB,操作起來也並不簡便。並且,他們的存取速度與store也明顯不是一個級別(雖然使用者幾乎感覺不到差異)。

方案

除類似autocomplate這類的sideways資料,所有從後端拉取的資料,以頁面級元件為單位,都存入store,做為伺服器資料本地快照。這樣,當使用者切換頁面時,只有view會被銷燬。每次使用者進入該頁面,首先會拿到一份快照資料,store同時向伺服器查詢最新資料。如有更新,可做提示有新資料(如新浪微博)。

而對於狀態(對,前面說了我把資料和狀態分別開來對待。資料指業務資料,而狀態,我理解為行為狀態),除非是全域性狀態,否則,管你是頁面級元件還是單元件,自個兒內部維護。

特別說明,store裡的資料,應當儘量保持是原始的伺服器資料快照,而不應該去做任何mutate,類似Redux的immutable思想。而對於add、del之類操作的結果,也不應當放入store,而只是一種狀態反饋,應當在元件內部消化。

這樣,我們的store裡就只有純粹的兩種東西:全域性狀態和業務資料(伺服器資料快照)。

更進一步,我們還可以藉助本地儲存把store做為本地快取,達到重啟app可立即恢復現場的效果。

優點

  1. 使用者體驗,對於切換頻率高的頁面,使用者體驗直線上升。設想一下,如果資料放到頁面元件內部,離開當前頁資料即被銷燬,當使用者一秒後再次返回該頁。。。

  2. 資源優化,減少對伺服器的請求,對於更新週期長的資料,例如使用者個人資訊,完全可以僅請求一次

  3. 可預測性,flux所提倡的資料可預測成為可能,各種資料追蹤工具得以大展身手(微信小程式開發工具的資料追蹤就挺不錯)

  4. 可讀性,component只有view邏輯,不摻雜modal邏輯,業務邏輯清晰易維護

  5. 擴充套件性強,例如需要加入許可權控制,進行資料過濾,在store層面就可以輕鬆解決。而如果業務資料在元件內部。。。

  6. 統一性,所有業務資料統一存取,管理方便。

缺點

再來看看持觀點1的人所反對的:

  1. store龐大,持觀點1的人首先反對的就是這個。但是,對於SPA來說,對於現代PC來說,你的SPA的store能達到以G為單位不?

  2. 編寫繁瑣,嗯,這算一個理由吧。不過,對於其所帶來的優點來說,這點犧牲並不算什麼吧?

  3. 資料時效,有人提到,一次性資料(比如訂單結算)不應被放入store。沒錯,這點我們可以在頁面destory時手動清理不是麼?

  4. 單store檔案難維護,有人提到,所有業務資料操作都在store裡,難維護。其實利用現在的構建工具,我們已經可以做到把各個頁面元件的store單獨切出來,構建時再合併,這並不會影響可維護性。

  5. 資料汙染,有人擔心,這麼多資料放到store裡,會不會造成汙染。對於這點,無論Redux和vuex,都是支援子store的。也就是名稱空間的概念。比如 store.pageModule1、store.pageModule2。再配合一些測試工具(如mocha)做重名檢測,這方面完全不是問題

還有什麼

實際開發過程中,還有一個經常遇到的,經常被人問起的問題:公共頁面元件容易載入到非自身資料。比如文章詳情頁,如果先瀏覽了文章1,再瀏覽文章2,有可能先顯示文章1的內容,會很怪異。其實這也是一個很容易解決的問題,進入一個頁面元件時,首先載入的其實是initialState,緊接著,flux才把store裡的資料推過來。這個時候,你應該做文章id校驗,只有是自身資料,才assign。

適用場景

記得有人說過這樣的話:“如果你不知道該不該用flux,那說明你並不需要它。” Redux的作者 Dan Abramov 說:“Flux 架構就像眼鏡:您自會知道什麼時候需要它。” 如果你的業務只是需要一個全域性變數倉庫,flux會不會過重?而對於大多數SPA場景,我想這個思路都是行得通的。另外,對於一次性資料比較多的應用,那這種思路或許也不太適合。

響應式store設想

我覺得最理想的狀態,flux架構還可以更進一步,把store做得更純粹一些,可以自行維護資料。具體做法是,ajax放到store層面,當請求的資料不存在或過舊時,自動拉取,而不需要通過actions來處理拉取資料的邏輯。

相關文章