store的組織是扁平化好,還是分層級樹狀的好?大型的項目store該怎麼組織?

如果純扁平的,那麼項目大了之後store會很多,store之間的層級關係不太明顯,如果按樹的形式來組織,那麼取某一個深層的store的數據要寫很長的rootStore.aStore.abStore…,還有store的劃分是應該以UI模塊來劃分,還是業務模塊來劃分


謝邀。 @顏什麼都不記得適 昨天晚上看球了,沒顧上,今早來答一下吧,請見諒。

這個問題非常好,題主能問這樣的問題,應該對 Redux 已經有了一定認識。每一個 React-Redux 開發者,在應用複雜度隨著產品迭代而指數增加時,或多或少都會面臨題主的困惑。

同時,通過題主的相關描述,我先指出一些描述不詳或存在的一些疏漏。

如果純扁平的,那麼項目大了之後 store 會很多

Redux 同早期 Flux 數據流結構的一個顯著不同就在於:一直以來,Redux 只提倡單一 store,所以題主說的「store 會很多」是不存在的,如果你設計出這樣的 Redux 數據流,那麼強烈建議先去 review 一下 Redux 單一 store 的思想。

當然,我認為這只是題主的「口誤」,應該想表達的意思是 store 的 state 直接子節點平鋪面會很多,或者這顆 state tree 將會非常的「寬」。

而這樣的狀況是好是壞呢?如果非要給一個是非論斷,那麼一定是好的。這正是 Redux 一直以來推崇的「扁平化」或「範式化」。

下面,我簡單來說明為什麼「扁平化」 大概率、大場景下 優於「分層級樹狀」。

設想你的 state 長這樣子:

{
foo: {
bar: {
baz: {
qux: ...
}
}
}
}

分層級很多,嵌套複雜。這樣存在的問題有:

  • 當某些數據需要在不同的地方出現時,就會存在必然重複。例如,可能存在很多 state 部分都要存儲同一份「用戶評論列表」,這樣需要花費很多心思去保障多處「用戶評論列表」數據狀態一致,否則就會造成頁面數據不同步的 Bug;
  • 嵌套深層的數據結構,會直接造成你 reducers 編寫複雜。比如,你想更新一個很深層次的數據片段,很容易代碼就變得醜陋。具體可以參考我的這篇文章:如何優雅安全地在深層數據結構中取值;
  • 造成負面的性能影響。即便你使用了類似 immutable.js 這樣的不可變數據類庫,最大限度的想保障深層數據帶來的性能壓力,那你是否知道 immutable.js 採用的 「Persistent data structure」 思路,更新節點會造成同一條鏈兒上的祖先節點的更新。更恐怖的是,也許這些都會關聯到眾多 React 組件的 re-render;

那麼,「扁平化」的數據結構是如何規避這些問題的,其優勢又體現在哪裡呢?

我打算用一個真實案例來說明。

為此,我剖析了 Twitter (其 WAP 端已經採用 React+Redux+PWA 技術棧)前端 Redux Store 的設計情況。先來整體感受一下:

可見,其 store 非常的「扁平化」,包含了眾多「範式」出來的數據信息。

接下來,Twitter(類比微博)的數據不可謂不複雜,類 feeds 流內容的展現核心就是頁面中每條 tweet 信息(推文)內容。我們先看這些推文的 state:

典型的根據 tweet id 來進行「扁平化」存儲。這樣做的收益也非常之明顯:

比如首頁時間線上,就可以直接通過 tweet id 來匹配推文,而避免了重複存儲。

類似的案例比比皆是。再比如依照這樣的設計,Twitter Store 對所有推文的拉取狀態也都單獨抽出為 fetchStatus,同樣使用了 tweet id 進行匹配,又一個典型「扁平化」的例子,看下圖:

關於 Twitter Store 更加深入的分析,我專門寫了一篇文章進行講解。建議感興趣的同學直接參考:了解 Twitter 前端架構 學習複雜場景數據設計;

總之,Twitter store 設計就是一個非常非常典型的「扁平化」思路。相信這不是該公司研發團隊的一時興起,而是經過廣泛討論、精心設計的。所以關於「扁平化」的優越性,我想很多人心中已經有數了。

Redux 官方的建議也很明確:

The recommended approach to managing relational or nested data in a Redux store is to treat a portion of your store as if it were a database, and keep that data in a normalized form.

但是所有的事情都「過猶不及」,脫離實際場景需求的討論都是耍流氓。在保證充分分析的前景下,還是要結合業務出發。

一個設計優良的 Store,涉及到方方面面,問答中提到的 state 結構只是其中一個環節。除此之外 reducers 的拆分,數據的 raw 程度,reselector 的設計,甚至文件目錄組織,都需要格外關心。只有自己實踐過,繞過彎路,才會有更多體會。

我做的真正的第一個(也是唯一一個)線上 React 項目:百度私信系統 http://jingyan.baidu.com/msg,整體 store 在某一時刻的快照如下:

可見數據嵌套不可謂不深,其中確實也有改良優化的餘地。可是對於開發效率,思維習慣的順暢,以及時間成本來看,這樣的缺陷設計也許在那一刻未必不是一個選擇。

同時我要補充的是,這些所謂的「最佳實踐」和「設計經驗」都是理論化的,也許看起來很抽象、晦澀,我的建議是「大膽地跟著感覺走吧」,因為有些「坑」總是要自己填平的,摸爬滾打的多了,這些先前令我們困惑的所謂「設計思想」都會變得清晰而深刻

最後,其實我在工作中使用 React 技術棧的機會並不多,拾人牙慧的同時,自己理解定有疏漏。這麼好的問題,希望大家一起交流,也懇請大佬們斧正。


好吧 蟹妖~

關於 store 如何組織的問題,其實本質是數據如何組織的問題,這個問題的答案你當然不可能在前端的書籍和文章中找到答案,朋友你需要一本

資料庫系統概論(第5版) (豆瓣)

哈哈哈,看我認真臉...

@Lucas HC 提到了範式化,而範式是資料庫理論的基礎知識。數據結構是否合理,是否冗餘,都可以通過範式的方式檢驗。如果不是計算機專業的盆友,不妨找本大學教材看看。

大學教材這個東西,無論如何你都可以在一個禮拜之內看懂60%。

然後你就發現你困惑的事情,在幾十年前就有人意識到,並且給出了解決理論。

關於前端數據的組織,我們能想到的一個極端就是完全按照表結構來做,完全扁平,通過外鍵連接,在業務層進行拉取組裝。

另一個極端則是前端數據層和 UI 完全對應,也就是說把邏輯耦合進了數據結構中,你把整顆樹畫出來就是個低配版的網頁了。

不管怎麼說,後端的數據層才是真正的數據層,前端的數據都是中間層,這個中間層裡面你想摻多少的業務邏輯都看個人喜好了,你可以一棵樹直接全都搞定,也可以在前端做數據和業務分離。

我的感覺來說,如果項目不大,也不涉及數據間複雜的計算依賴關係,前端數據層更貼合 UI 會用起來比較方便。如果內容太多,那還是做純粹一點的介面,畢竟有非常成熟的資料庫理論可以給你提供支持。

前端數據層更貼合 UI 會用起來比較方便,但是我們也需要給工程化讓步,這種數據冗餘是否是對項目有害,要看數據和項目的規模。

直覺來說就是,你覺得數據怎麼冗餘這麼多,嵌套這麼多,我不開心了,那就拆平一點。

p.s. 最近考慮要不要開一個 live 講講前端數據管理,本來想說你們點贊我就去開,然後 @知乎小管家 警告我騙贊...

反正你們贊不贊我都已經申請了...【live 預告】前端數據管理與前端框架選擇

p.s. @知乎小管家 感謝提醒,順便說一下,你們能不能管一管那個發"前端是一門技術,也是一門美麗的藝術"的團伙啊...


在瀏覽器里實現一個簡陋的資料庫即可,偏扁。


一般原則是扁平化。但也取決於需求,如果數據源頭就是一個複雜的tree,沒有必要為了刻意扁平化而再轉換數據。

combineReducers用得比較多。有當成namespace來用的傾向。


對於大型應用,當然是扁平化好,redux 也推薦範式化的state 。

類似於下面這樣

{
collection: {simpleDomin:[ids]},
simpleDomain: {id: "", name: ""}
entities : {
simpleDomin : {
569848: {
id: "569846",
name: "aefg"
}
},
}
}

這樣的查詢複雜度是 O(1);

具體可以移步我的另一個回答 pawn:react是先寫view,還是先寫store?


以modules,namespace,樹狀結構來劃分,都是一個意思。建議不要扁平化。

至於取數據時字元串的長短,我感覺這都無所謂,項目大到這個地步,可讀性更重要。

以UI還是業務劃分,不同場景下不一樣,視情況而定。


要求你扁平化說白了就是給強行immutable帶來的坑爹事情擦屁股而已,包裝的這麼高大上


項目小: 直接扁平化,範式就好了

項目一般: 扁平化加模塊化就好了,每個模塊數據獨立但仍單一store。

項目大且每個模塊獨立: 扁平化,模塊化,還可以每個模塊獨自createStore,然後如果有需要全局狀態則直接傳入全局store到下層使用,然後項目全局暴露操控全局store的方法(其實就是包裝一層全局store的dispatch),例如控制全局loading

看到題主沒說是redux還是mobx,上面回答是個人覺得的redux,如果是mobx可以:

按照UIstore,dataStore。前者呢是頁面狀態,後者呢是獲得的數據。也最好按照扁平的來處理。然後如果項目大且模塊之間完全獨立,也可以每個模塊一個store。。只是共享部分全局store即可。


http://redux.js.org/docs/faq/OrganizingState.html 去看官方文檔吧


是否扁平化這個是建立在業務的複雜度的基礎上,之前開始設計store的時候也糾結是否扁平化的越多越好,最後是根據業務、UI、驗證分別對應不同的Object。這樣設計目前沒有啥大問題,這個就要需要在實踐中不斷的糾正。


這個東西主要看項目規模和開發周期來決定吧

小項目短平快就貼合ui做數據

大項目長周期就盡量把數據組織的規範一些 以利於後期維護


偏向展示的,用嵌套吧,循環方便。

如果有更新需求,建議用範式化展平,不然redux的reducer很難寫。或者乾脆別有redux,用mobx就好了。


扁平化。 結構太深, reducer的邏輯寫的累人


推薦閱讀:

新手學習前端開發加了很多技術群有必要天天看群聊天記錄學習嗎?
截止到2017年7月,手淘內部還在用vue嗎,有替換成react嗎?
如何看待知乎使用 React 重構?

TAG:前端開發 | 狀態管理 | React | Redux | MobX |