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