關於redux在項目運用中的一些問題?

項目用的dva,現在還在迭代,發現store越來越大,該怎麼解決?怎樣組織store才能提高性能,避免一些無效的渲染?而且大家對於redux的store和react的state都怎麼取捨,依據是什麼?


提主談到 dva,我分享使用 dva 的一點經驗,從後往前回答。

1. 盡量使用 PureComponent,配合 Immutable,一個組件就是一個 Immutable.Record 的 View 化。Record 沒變化,就不會重新渲染。

2. 在 model 里維護的應當是描述實體之間的關係的數據結構,而不直接維護實體本身。

舉個栗子。一個 users 的 model,state 應當是 { list: List&},或者其他啥的結構。用戶實體本身的數據結構不要丟到 model 里來維護。(雖然實際仍存在 model里)。 model 只剩下數據結構,實體的 CURD 分別對應相應 Immutable 結構的操作。

3. 每個 model 對應一個或多個的 Container Component ,負責把模型中的實體關係渲染成視圖。

4. 複雜組件必須有內部狀態的,要維護一個 props 到 state 的映射關係。state 當 model 用。繼續按照上面 2、3 的搞法細分。

5. 最後,router 也是一種 state。參照 https://github.com/dvajs/dva-example-user-dashboard/blob/master/src/router.js 的方法搞一搞,更靈活。


謝邀

尤小右最近的 live 中有講到 store 的使用,建議聽一聽

叔叔的文章 單頁應用的數據流方案探索 - 知乎專欄 精讀一下

還有我們的精讀 精讀民工叔單頁數據流方案 - 知乎專欄

你的場景,我不清楚,store 很大是什麼概念,如果只是請求多,還是比較好處理的,可以抽一層 service 層。如果都在前端抽象實體,那麼建議抽一層數據處理層,用 rx


react作者說過:

如果prod不卡你就不要優化,dev卡那是因為有dev usage code。

對於數據劃分,如果是通用的存store,非通用的放state。


1. 發現store越來越大,該怎麼解決?

隨著業務複雜度增加,store變大天經地義而且並不可怕,關鍵在於把管理store的複雜度控制在一定範圍。

- 縱向分割:將整個store按照業務單元拆分為幾個模塊單元,每個單元都包含有相對應業務的store、reducer以及必要的saga(redux-saga)。通過模塊化分治的手段,讓store更清晰,讓你維護大型應用時候更加專註,更加可控。

請參考《How to structure real world Redux/React application》 以及erikras/ducks-modular-redux

- 橫向分割:將模塊store分為領域模型,應用狀態和ui,更加清晰和規範的存儲和處理邏輯。參考Basic Reducer Structure

{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}

當然這麼做又會有新的挑戰:如何劃分模塊?如何跨模塊調度?如何父子模塊通信?那是另一個大話題。

2. 怎樣組織store才能提高性能,避免一些無效的渲染?

- 使用React.PureComponent,它會幫你對props和state做一次簡單淺比較,大多數情況下已經夠用了。

- 如果數據結構很深,你又希望有性能上的提升,可以考慮使用immutable數據,實現真正的減少無效渲染。它通過structural sharing讓追蹤變化的成本變得很低(精讀 Immutable 結構共享 - 知乎專欄)。如果你覺得immutablejs的api太繁瑣,可以使用官方推薦的kolodny/immutability-helper,也可以使用我們團隊的ProtoTeam/immutability-helper-x,更爽的使用體驗,最佳推薦!

3. 對於redux的store和react的state都怎麼取捨,依據是什麼?

- 數據需要持久化、共享,那就放到redux

- 臨時數據、component內部自成一體,且沒有外界交互,那就放在state

聽一聽來自gaearon(redux作者)的想法:

1.

Question: How to choose between Reduxamp;amp;amp;amp;#x27;s store and Reactamp;amp;amp;amp;#x27;s state? · Issue #1287 · reactjs/redux

2.

What are the disadvantages of storing all your state in a single immutable atom? · Issue #1385 · reactjs/redux


別花腦子想那麼多專業性的理論知識,實踐告訴我們,複雜的事情簡單化,可以早早寫完代碼來知乎逛,可以早點寫完代碼寫自己的博客。

很簡單的選擇:優先選擇state,store為輔。

一開始使用store的時候,我也認為要盡量全部丟到store來管理,這也是被理論給誤導了,導致我寫代碼的效率非常低,後來,為了不加班(好久沒體驗過加班的屎味了),我反其道而行,不能在state處理的就丟到store去,或者全局的state也丟到store去,這樣減少了很多工作量。

喜歡加班的程序員們多搞些複雜的框架,完全相信官方教程去做 ,保證你天天加班。


其實redux的思想是組件中不應該有state,都扔給store。但是那樣好麻煩,最近在用react + redux + redux-saga,我們是這樣弄的,組件內部的state可以有,跨組件的state,扔給redux。


在我的項目實踐里,通過store拆分來解決store過大的問題。很多人覺得redux在全局只有一個store,只要兩個組件有狀態共享,就把這個狀態扔到全局的store里,這樣會導致store非常雜亂。可以保留一個全局store的同時,再按照功能區塊劃分,創建多個store,每個store只負責該區塊的狀態管理。


編寫好的組件,第一個解決的就是數據問題。一個組件中包含的數據有多種,一種分類就是UI state和Domain state。

先來說說Domain state,它就是我們正常的業務數據,比如說消息數據,我們會通過一些轉換然後在界面上顯示,當然你也可以去修改。而UI state則是增對組件本身的一些數據,比如說某個按鈕的顯示,某個checkbox的選擇,這些數據一般不會和其他組件共享。

另一種分類是Local state/Global state。

Local state和我們上面說的UI state有一個共同點,就是不會和其他組件共享,但是還有一類數據是屬於Local state的,那就是表單的輸入數據。這些數據在提交之前只要所屬組件知道就可以了。另外一種是Global state,這類數據是從父組件中傳遞下來的,修改之後還可能需要調用回調方法通知其他組件。

這裡為什麼要說說state的類別呢,這個其實是和下面說的redux有些關係的,redux管理的state應該是Domain state或者Global state,對於UI state和Local state就不要放進去了,自己setState就可以了。因為畢竟使用redux還是有開銷的。


1:domainData 能夠區分業務領域,但是不能解決store越來越大,也僅僅只是讓你比較清晰的知道全局store的props來自哪個domain。

2:能夠內部的state,盡量內部state,我是這麼覺得的,只要不牽扯遠距離的component connect。

吐槽一下我司,什麼鬼都扔進redux,看的一坨屎在redux dev tool裡面,真心頭大


這裡有三個問題,我說下我的個人經驗,具體還要在實際場景中在考慮,畢竟一千個人眼中有一千個草泥馬。

第一個和第三個問題有些關聯,我一起說下:

  • 數據放入store里後的邏輯維護是比在state中高的,沒必要放入store的,不放入
  • 如果一個組件明確擁有這份數據,那數據就應該在state里
  • 無主的數據放入store,即不能明確歸屬的數據,也可以說是共享數據
  • 共享數據、實體數據(或者叫領域模型數據)即使只有一個組件在用,未來也很有可能被共享使用,需要放入store(比如用戶信息,一開始可能只需要展示個用戶名,但不久的將來某個小角落裡肯定會需要根據用戶信息展示下內容這樣~)

第二個問題:

其實PureComponent配合immutable已經避免了很多不必要的刷新了,如果還有必要追求極致:

  • 場景1:有些數據其實無關視圖,但他的更新也會重新觸發render,需要自定義shouldComponentUpdate來判斷render需要用到的那些屬性,這裡有個acdlite/recompose倉庫提供了一些高階組件來幫助實現這個功能
  • 場景2:有部分屬性會導致哪怕是意義一樣,也會重複render,不過這種場景需要注意的情況很多,有時候我自己都*^F(%$。。。

// bad
&

// good
const style = { margin: 5 }
const onChange = this.onChange.bind(this)
&


第一個問題: 減少渲染 (實質是對shouldComponentUpdate的控制)

首先: 前面 @陸離 講的很好,提到的PureComponent用起來,簡單的說就是它自帶shadowEqual的shouldComponentUpdate,可以看看 在React.js中使用PureComponent的重要性和使用方式 - 知乎專欄, 想想為什麼要使用PureComponent;

其次: 看看你的store的理解,盡量在保持每個model層state對象不要過深,一般保持在三層以內,當然這也和你如何在Container中使用connect去derive state有關,這時候上面提到的PureComponent就起作用了;當然你可以在shouldComponentUpdate中自己判斷,但是會造成一定的消耗;

第二個問題: redux的store和react的state(實質是全局狀態和局部狀態的選擇)

這個主要是看你的需求,如果你覺得某個組件的狀態不用要或者只需要在內部使用(如Select),那麼就用組件內state;至於把存在redux里,我所遇到的需求是要讓當前狀態可以復現或者其他container/component希望共享;

我會亂說 逃~

========

補充一句: 千萬別把Immutable和ImmutableJS混為一談。


Question: How to choose between Redux#x27;s store and React#x27;s state? · Issue #1287 · reactjs/redux

考慮下SSR的需求.


可以是immutable,不可變數據結構


個人的想法是:

1、組件間共同控制的東西放入redux中,也就是一些共享狀態。state只存組件特有的或者一些樣式相關。

2、store儘可能的細分,使扁平。這樣,用reducer後改變某個store子對象後不會影響其他組件的store對象,不觸發渲染。Immutable還沒用,暫時用的是Object.assign或者解構賦值,生成新對象。不好的就是在shouldComponentUpdate中的一些深比較比較麻煩,沒有immutableJS提供的api。


Mobx + 非同步載入 + inject 可以解決大部分問題


推薦閱讀:

Angular2 相比 React 技術棧有什麼具體的優勢?
前端框架有哪些典型問題?
很迷茫,不知道自己現在是要繼續學習 React.js 還是系統地學習 JS?
公司團隊有自己專職的UI設計師,但是前端團隊成員js能力薄弱,是否需要用bootstrap?
2018年一個合格的前端應該是什麼樣的?

TAG:前端性能優化 | 前端框架 | React | Redux |