阅读react-redux源码(六) - selectorFactory处理store更新
- 閱讀react-redux源碼 - 零
- 閱讀react-redux源碼 - 一
- 閱讀react-redux源碼(二) - createConnect、match函數(shù)的實現(xiàn)
- 閱讀react-redux源碼(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories
- 閱讀react-redux源碼(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates
- 閱讀react-redux源碼(五) - connectAdvanced中store改變的事件轉(zhuǎn)發(fā)、ref的處理和pure模式的處理
- 閱讀react-redux源碼(六) - selectorFactory處理store更新
store中的無關(guān)變動就是通過selectorFactory來阻止的。store中的state有很多,而當(dāng)前組件關(guān)注的state不會是全部,例如state:{a: 1, b:2}。組件只關(guān)注屬性a,但是屬性b修改了,因為store.subscribe監(jiān)聽的整個state變化,state確實變化了,但是我關(guān)注的部分沒有變,也就是b: 2沒變,所以當(dāng)前業(yè)務(wù)組件如果是pure模式則不應(yīng)該更新,其中的處理邏輯則在selectorFactory.js中。
頂部函數(shù)很簡單:
export default function finalPropsSelectorFactory(dispatch,{ initMapStateToProps, initMapDispatchToProps, initMergeProps, ...options } ) {const mapStateToProps = initMapStateToProps(dispatch, options)const mapDispatchToProps = initMapDispatchToProps(dispatch, options)const mergeProps = initMergeProps(dispatch, options)if (process.env.NODE_ENV !== 'production') {verifySubselectors(mapStateToProps,mapDispatchToProps,mergeProps,options.displayName)}const selectorFactory = options.pure? pureFinalPropsSelectorFactory: impureFinalPropsSelectorFactoryreturn selectorFactory(mapStateToProps,mapDispatchToProps,mergeProps,dispatch,options) }上一章看到的內(nèi)容是通過createChildSelector的調(diào)用會返回一個childSelector,而childSelector的調(diào)用需要入?yún)tate和wrapperProps,然后融合成一個整體的props傳遞給被包裹的組件。
function createChildSelector(store) {return selectorFactory(store.dispatch, selectorFactoryOptions) }調(diào)用的就是方法finalPropsSelectorFactory得到的返回值是:
selectorFactory(mapStateToProps,mapDispatchToProps,mergeProps,dispatch,options )會被如此調(diào)用:
childPropsSelector = createChildSelector(store) childPropsSelector(store.getState(), wrapperProps)childPropsSelector(store.getState(), wrapperProps)的掉用會返回一個實際的會傳遞給被包裹的業(yè)務(wù)組件的完整的props。
是什么和怎么用交代清楚,開始查看代碼,如何實現(xiàn)這些功能的。
上面的代碼需要處理兩種情況,一種是options中的pure設(shè)置為ture的pure模式,一種是非pure模式,整個代碼需要處理這兩種情況,而當(dāng)前代碼的處理方式邏輯十分清晰。
兩種模式并不是完全不能復(fù)用代碼,例如當(dāng)前的組裝各個部分的邏輯就是相同的,而各個被抽出來的部分也是公用的,例如:mapStateToProps、mapDispatchToProps、mergeProps、dispatch、options,這些都是共用的。兩種模式都是通過這些入?yún)頉Q定被合成的props的。所以處理兩種條件分支的情況提取他們公共的部分然后通過入?yún)⒌姆绞絺魅虢M裝不失為一個好的方法。
頂部函數(shù)finalPropsSelectorFactory的目的很明顯,就是為了組裝這些參數(shù)得到一個selector用于計算返回真正的props。
如果不是pure模式則很簡單是一個合并三方的函數(shù),分別合并了mapStateToProps的返回值,mapDispatchToProps的返回值和ownProps,父元素傳遞給子元素的props,實現(xiàn)方法如下:
export function impureFinalPropsSelectorFactory(mapStateToProps,mapDispatchToProps,mergeProps,dispatch ) {return function impureFinalPropsSelector(state, ownProps) {return mergeProps(mapStateToProps(state, ownProps),mapDispatchToProps(dispatch, ownProps),ownProps)} }其中默認的mergeProps函數(shù)的實現(xiàn)很簡單:
export function defaultMergeProps(stateProps, dispatchProps, ownProps) {return { ...ownProps, ...stateProps, ...dispatchProps } }就是一個合并三方返回合并結(jié)果的函數(shù)。
主要看pureFinalPropsSelectorFactory的實現(xiàn),在這個函數(shù)中封裝了重要的內(nèi)容,完成對比阻止store更新引起的不必要更新的核心就在這個函數(shù)里面。
export function pureFinalPropsSelectorFactory(mapStateToProps,mapDispatchToProps,mergeProps,dispatch,{ areStatesEqual, areOwnPropsEqual, areStatePropsEqual } ) {let hasRunAtLeastOnce = falselet statelet ownPropslet statePropslet dispatchPropslet mergedPropsfunction handleFirstCall(firstState, firstOwnProps) { ... }function handleNewPropsAndNewState() { ... }function handleNewProps() { ... }function handleSubsequentCalls(nextState, nextOwnProps) { ... }return function pureFinalPropsSelector(nextState, nextOwnProps) {return hasRunAtLeastOnce? handleSubsequentCalls(nextState, nextOwnProps): handleFirstCall(nextState, nextOwnProps)} }pureFinalPropsSelectorFactory 函數(shù)返回一個函數(shù)pureFinalPropsSelector。這個函數(shù)的運行又分為兩種情況,之中是第一次運行,一種是非第一次運行。第一次運行執(zhí)行函數(shù) handleSubsequentCalls(nextState, nextOwnProps),非第一次運行則運行 handleFirstCall(nextState, nextOwnProps)。
handleFirstCall函數(shù)的實現(xiàn):
function handleFirstCall(firstState, firstOwnProps) {state = firstStateownProps = firstOwnPropsstateProps = mapStateToProps(state, ownProps)dispatchProps = mapDispatchToProps(dispatch, ownProps)mergedProps = mergeProps(stateProps, dispatchProps, ownProps)hasRunAtLeastOnce = truereturn mergedProps}存儲一些原始數(shù)據(jù),例如firstState、firstOwnProps和計算出來的數(shù)據(jù),例如:stateProps、dispatchProps和mergedProps。最后將至少執(zhí)行一次設(shè)置為true,并且返回所有數(shù)據(jù)的merge結(jié)果。
因為hasRunAtLeastOnce為true所以之后執(zhí)行方法pureFinalPropsSelector真正執(zhí)行的則是handleSubsequentCalls。
function handleSubsequentCalls(nextState, nextOwnProps) {const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)const stateChanged = !areStatesEqual(nextState, state)state = nextStateownProps = nextOwnPropsif (propsChanged && stateChanged) return handleNewPropsAndNewState()if (propsChanged) return handleNewProps()if (stateChanged) return handleNewProps()return mergedProps}首先對比下是props變了,還是state變了,還是props和state都變了。
如果都變了執(zhí)行handleNewPropsAndNewState,如果props變了執(zhí)行handleNewProps,最后handleNewProps。
其中對比方法默認是:
areStatesEqual = strictEqual, areOwnPropsEqual = shallowEqual, areStatePropsEqual = shallowEqual, areMergedPropsEqual = shallowEqual,如果都變了,handleNewPropsAndNewState:
function handleNewPropsAndNewState() {stateProps = mapStateToProps(state, ownProps)if (mapDispatchToProps.dependsOnOwnProps)dispatchProps = mapDispatchToProps(dispatch, ownProps)mergedProps = mergeProps(stateProps, dispatchProps, ownProps)return mergedProps}重新計算mergedProps并返回。
如果只有新的props變了,如果mapStateToProps和mapDispatchToProps依賴props則需要重新計算stateProps和dispatchProps,然后重新計算mergedProps。
function handleNewProps() {if (mapStateToProps.dependsOnOwnProps)stateProps = mapStateToProps(state, ownProps)if (mapDispatchToProps.dependsOnOwnProps)dispatchProps = mapDispatchToProps(dispatch, ownProps)mergedProps = mergeProps(stateProps, dispatchProps, ownProps)return mergedProps }如果只有state改變的話:
function handleNewState() {const nextStateProps = mapStateToProps(state, ownProps)const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)stateProps = nextStatePropsif (statePropsChanged)mergedProps = mergeProps(stateProps, dispatchProps, ownProps)return mergedProps }主要看這里,這里就是處理store中state的改變引起的更新,這里會重新計算stateProps,然后會去嚴格比較,如果改變了則會重新計算mergedProps,如果沒有變則會將舊的返回出去,也就是說外面對比即使是嚴格對比也會是相等的,也就不會引起組件更新。
這個實現(xiàn)結(jié)構(gòu)層次分明,邏輯清晰。首先看設(shè)置了什么模式,pure還是非pure。如果是pure實現(xiàn)中還分為第一次執(zhí)行還是非第一次執(zhí)行,如果是第一次則收集數(shù)據(jù),非第一次需要對比數(shù)據(jù)。還清晰的將真正傳給業(yè)務(wù)組件的props分為了三個類型,一個是來自state的一個是來自dispatch的還有一個來自父組件傳給業(yè)務(wù)子組件的。將這三方合并在一起傳遞給業(yè)務(wù)子組件。
而其中做的優(yōu)化還有很多,例如props改變的時候,如果mapStateToProps和mapDispatchToProps不依賴props則不會重新去計算。
整個設(shè)計也是依賴注入的一個例子,頂層函數(shù)finalPropsSelectorFactory中需要用的元素都是通過參數(shù)注入進來的,需要找的話需要往上兩級才能找到來源。
到這里pure的兩層優(yōu)化父組件render引起子組件不必要的更新,通過React.memo來阻止,而不相關(guān)的store中state的更新則被函數(shù)handleNewState阻止,如果發(fā)現(xiàn)沒變則返回老的mergedProps。
- 閱讀react-redux源碼 - 零
- 閱讀react-redux源碼 - 一
- 閱讀react-redux源碼(二) - createConnect、match函數(shù)的實現(xiàn)
- 閱讀react-redux源碼(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories
- 閱讀react-redux源碼(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates
- 閱讀react-redux源碼(五) - connectAdvanced中store改變的事件轉(zhuǎn)發(fā)、ref的處理和pure模式的處理
- 閱讀react-redux源碼(六) - selectorFactory處理store更新
總結(jié)
以上是生活随笔為你收集整理的阅读react-redux源码(六) - selectorFactory处理store更新的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阅读react-redux源码(五) -
- 下一篇: 阅读react-redux源码(七) -