使用React-Redux感悟

說來也慚愧,接觸Redux一年多了,卻沒有深入的去研究過,平時只注重使用層面的東西,認爲夠用即可。計算機行業裏面流行這樣一句話“欠的總是要還的”,所以之前欠下的賬現在就得來還。

開始之前的必須要說明一下,Redux本身和React之間並沒有什麼關聯,它是一個通用Javscript App模塊,用做App State的管理。要在React的項目中使用Redux,比較好的方式是藉助react-redux這個庫來做連接,這裏的意思是,並不是沒有react-redux,這兩個庫就不弄一起用了,而是說react-redux提供了一些封裝,一種更科學的代碼組織方式,讓我們更舒服地在React的代碼中使用Redux。

之前,我在很多技術文章上看到過關於react-redux的介紹,說“如果你不知道redux這個東西是什麼,那你就不需要使用它”。當時並沒有覺得這句話有多大問題,可是後來真正開始做項目,接觸redux這個東西之後,覺得這句話應該稍微改一下“如果開發的是一個小項目,沒有複雜的產品需求,你不知道redux這個東西是什麼,那你就不需要使用它”。言外之意就是,正常開發react-native項目是必須要學會的。爲什麼這麼說呢?第一,做APP難免需要使用緩存,我們不可能手動的藉助異步存儲asyncStory一個個將數據;第二,動態的刷新頁面,比如這個頁面的數據變化了,同時需要更新其他頁面的數據,不可能大量使用的拋通知的方法;等等

談完了redux的概念、必要性以及使用場景,下面真正的來介紹redux-redux這個東西!

1.Provider
Provider其實作用很簡單,就是一個外層容器,使原來整個應用成爲Provider的子組件,將從createStore返回的store放入context中,使子集可以獲取到store並進行操作;還記的我們在使用的時候都是this.props.dispatch(…);其實仔細想一下dispatch是store裏面的方法,那麼爲什麼可以使用this.props來調用呢?很明顯得出一個結論,store或者store裏面的某些屬性被合併到this.props裏面。可能,這個地方說這個有點早,不過完全可能證明Provider是將store傳遞到根節點及其子集。

2.connect
這個東西要花點功夫,詳細說一說了。接着上面的紅色部分來講,爲什麼store裏面的東西到這個地方,變成了用this.props來調用?它包在我們的容器組件的外一層,它接收上面 Provider 提供的 store 裏面的 state 和 dispatch,傳給一個構造函數,返回一個對象,以屬性形式傳給我們的容器組件。這個就是connect的功勞了!

這個地方可能理解起來有點吃力,先舉個例子。假設有一間很大的封閉的房間,而且房間只有一個口(connect),房間裏面養了很多的動物(組件),這個時候,有一隻狗餓了,它就發出叫聲(action),外面飼養員(reducer)聽到之後,就知道原來是狗餓了,就通過那個口向裏面拋一點狗糧(state)。扔進去的狗糧,並不會引起動物們的哄搶,因爲只有那隻狗才認識(也就說state變化的時候,並不是所有的組件都會render)。如果裏面有一個動物發出的叫聲飼養員根本聽不出來是什麼動物發出的,也不會去給它找吃的,因爲根本不知道它要什麼(也就是說,組件發出action的信號,reducer必須能解析纔可以,否則沒什麼意義)。

接下來,就會出現下面幾個問題?

(1)React組件如何響應store的變化?
把connect返回的函數叫做Connector,它返回的是內部的一個叫Connect的組件,它在包裝原有組件的基礎上,還在內部監聽了Redux的store的變化,爲了讓被它包裝的組件可以響應store的變化:

(2)爲什麼connect選擇性的merge一些props,而不是直接將整個state傳入?
我們connect的是某個Container組件,它並不承載所有App state,然而我們的handler是響應所有state變化的,於是我們需要優化的是:當storeState變化的時候,僅在我們真正依賴那部分state變化時,才重新render相應的React組件,那麼什麼是我們真正依賴的部分?就是通過mapStateToProps和mapDispatchToProps得到的。

(3)pure優化的是什麼?
顧名思義,就是在發現store變化之後,而且也通過connect將數據merge到props中了,但是這個數據有可能跟上一次是一樣的,也就是有可能dispatch多次相同數據的action,要不要重新render,目前的處理是render(個人覺的沒有必要再次render)。具體優化的方式就是在shouldComponentUpdate中做檢查,如果只有在組件自身的props改變,或者mapStateToProps的結果改變,或者是mapDispatchToProps的結果改變時shouldComponentUpdate纔會返回true,檢查的方式是進行shallowEqual的比較。

最後,再來介紹一下4個重要connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])的方法。

1.mapStateToProps
[mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定義該參數,組件將會監聽 Redux store 的變化。任何時候,只要 Redux store 發生改變,mapStateToProps 函數就會被調用。該回調函數必須返回一個純對象,這個對象會與組件的 props 合併。如果你省略了這個參數,你的組件將不會監聽 Redux store的變化。如果指定了該回調函數中的第二個參數 ownProps,則該參數的值爲傳遞到組件的 props,而且只要組件接收到新的 props,mapStateToProps 也會被調用。

2.mapDispatchToProps
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果傳遞的是一個對象,那麼每個定義在該對象的函數都將被當作 Redux action creator,而且這個對象會與 Redux store 綁定在一起,其中所定義的方法名將作爲屬性名,合併到組件的 props 中。如果傳遞的是一個函數,該函數將接收一個 dispatch 函數,然後由你來決定如何返回一個對象,這個對象通過 dispatch 函數與 action creator 以某種方式綁定在一起(提示:你也許會用到 Redux 的輔助函數 bindActionCreators())。如果你省略這個 mapDispatchToProps 參數,默認情況下,dispatch 會注入到你的組件 props 中。如果指定了該回調函數中第二個參數 ownProps,該參數的值爲傳遞到組件的 props,而且只要組件接收到新 props,mapDispatchToProps 也會被調用。

3.mergeProps
[mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了這個參數,mapStateToProps() 與 mapDispatchToProps() 的執行結果和組件自身的 props 將傳入到這個回調函數中。該回調函數返回的對象將作爲 props 傳遞到被包裝的組件中。你也許可以用這個回調函數,根據組件的 props 來篩選部分的 state 數據,或者把 props 中的某個特定變量與 action creator 綁定在一起。如果你省略這個參數,默認情況下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的結果。

4.options
[options] (Object) 如果指定這個參數,可以定製 connector 的行爲。
[pure = true] (Boolean): 如果爲 true,connector 將執行 shouldComponentUpdate 並且淺對比 mergeProps 的結果,避免不必要的更新,前提是當前組件是一個“純”組件,它不依賴於任何的輸入或 state 而只依賴於 props 和 Redux store 的 state。默認值爲 true。
[withRef = false] (Boolean): 如果爲 true,connector 會保存一個對被包裝組件實例的引用,該引用通過 getWrappedInstance() 方法獲得。默認值爲 false。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章