注:這篇文章只是講解React Redux這一層,並不包含Redux部分。Redux有計劃去學習,等之後學習了Redux源碼之後再作分析
注:代碼基於如今(2016.12.29)React Redux的最新版本(5.0.1)segmentfault
這裏有四個參數:工具
mapStateToProps, mapDispatchToProps, mergeProps都是通過mapDispatchToProps, mapStateToProps, mergeProps封裝過的學習
displayName是option裏面傳入的
主要作的是檢查傳入的mapStateToProps,mapDispatchToProps,mergeProps是否存在,因爲這裏的對象是通過幾個map方法封裝過的,因此不存在就說明開發傳入的值是錯誤的。同時檢查是否有dependsOnOwnProps這個屬性,若是沒有給一個warning.spa
import warning from '../utils/warning' function verify(selector, methodName, displayName) { if (!selector) { throw new Error(`Unexpected value for ${methodName} in ${displayName}.`) } else if (methodName === 'mapStateToProps' || methodName === 'mapDispatchToProps') { //只檢查mapStateToProps和mapDispatchToProps, 由於mergeProps方法不須要 if (!selector.hasOwnProperty('dependsOnOwnProps')) { warning( `The selector for ${methodName} of ${displayName} did not specify a value for dependsOnOwnProps.` ) } } } export default function verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, displayName) { verify(mapStateToProps, 'mapStateToProps', displayName) verify(mapDispatchToProps, 'mapDispatchToProps', displayName) verify(mergeProps, 'mergeProps', displayName) }
這裏主要負責獲取處理過的mapStateToProps, mapDispatchToProps, mergeProps和傳入的options,來進行props的合併,最後返回合併後的結果。其中,當pure爲true的時候,會對props進行存儲,便於下一次比較,若是經過比較兩個相同,那麼就不改變props對象,減小沒必要要的re-render。code
在connectAdvanced.js裏面看到這麼一段註釋:對象
selectoryFactory方法返回的是一個function,這個function的做用是根據Redux Store state, props和dispatch計算新的props. 在connectAdvanced中會提供dispatch給selectorFactory,以便selectorFactory能夠對actionCreator進行綁定。connectAdvanced獲取的option配置會直接被傳給selectorFactory,其中就包含了displayName和wrappedComponent(其實還有一些對比的方法在裏面)。ci
selectorFactory負責記錄全部的狀態(props, store state, dispatch, mergedProps),以便在部分狀態發生改變,而不影響組件渲染的時候,能夠避免沒必要要的渲染。開發
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 : impureFinalPropsSelectorFactory return selectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch, options ) }
這裏只是給mapStateToProps, mapDispatchToProps, mergeProps傳入dispatch和options對象,而後根據pure的值傳給不一樣的方法進行處理。get
若是pure是true, 那麼selectorFactory返回的selector會負責存儲最後結果。若是結果沒有發生改變,那麼connectAdvanced的shouldComponentUpdate就會返回false。
若是pure是false, 那麼selector永遠會返回一個新的對象,同時shouldComponentUpdate永遠都返回true
這個factory方法會返回一個function,接收Redux Store和ownProps做爲參數。做用是,每次store或ownProps發生改變之後,調用這個返回的function,獲取更新後的最終props。
export function impureFinalPropsSelectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch ) { return function impureFinalPropsSelector(state, ownProps) { return mergeProps( mapStateToProps(state, ownProps), mapDispatchToProps(dispatch, ownProps), ownProps ) } }
根據pure等於false的狀況,這裏會永遠返回一個新的對象。存粹的、不加任何判斷的調用mergeProps對幾個props的結構進行合併。
這裏返回的值的格式是:(state, ownProps)=>final props
。
export function pureFinalPropsSelectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch, { areStatesEqual, areOwnPropsEqual, areStatePropsEqual } ) { let hasRunAtLeastOnce = false // 是不是第一次調用,第一次調用不須要作是否改變的檢查 let state // 記憶上一次的state let ownProps // 記憶上一次的ownProps let stateProps // 記憶mapStateToProps返回的props let dispatchProps // 記憶mapDispatchToProps返回的props let mergedProps // 記憶最後合併後的結果 // 第一次調用的時候,純粹記住全部的結果 function handleFirstCall(firstState, firstOwnProps) { state = firstState ownProps = firstOwnProps stateProps = mapStateToProps(state, ownProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) hasRunAtLeastOnce = true return mergedProps } // 當兩個都發生改變。。。 function handleNewPropsAndNewState() { stateProps = mapStateToProps(state, ownProps) // ownProps發生了改變,確定須要調用獲取新的props if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps } // 若是隻有父組件傳入的props發生了改變,那麼須要根據dependsOnOwnProps來進行更新 function handleNewProps() { if (mapStateToProps.dependsOnOwnProps) stateProps = mapStateToProps(state, ownProps) if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) // 因爲ownProps發生了改變,因此不須要進行檢查,直接調用mergeProps方法 mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps } // 若是隻有Redux store state發生了改變,那麼只用更新mapStateToProps的返回值,由於dispatchProps和Redux State無關 function handleNewState() { const nextStateProps = mapStateToProps(state, ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps } // 除第一次調用外,每次都須要對各類結果進行檢查,而後記錄必要的結果 function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps) // 檢查ownProps是否發生改變 const stateChanged = !areStatesEqual(nextState, state) // 檢查Redux store state是否發生改變 state = nextState ownProps = nextOwnProps // 根據改變的不一樣,調用不一樣的方法。減小沒必要要的運算 if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps } return function pureFinalPropsSelector(nextState, nextOwnProps) { return hasRunAtLeastOnce ? handleSubsequentCalls(nextState, nextOwnProps) : handleFirstCall(nextState, nextOwnProps) } }
當pure等於true的時候,須要作出各類檢查來斷定是否須要調用方法,來獲取新的props.
當Redux state發生改變,ownProps沒變的時候
1) 因爲mapDispatchToProps並無基於Redux State,因此dispatchProps是須要進行更新的。2) 而mapStateToProps是基於Redux State的,因此須要調用mapStateToProps方法或許"新的"stateProps。因爲State發生改變,並不必定會形成返回結果的改變,因此須要根據檢查後的結果來斷定是否調用mergeProps方法。
當OwnProps發生改變,Redux State沒有改變的時候
1) 因爲mapDispatchToProps和mapStateToProps均可能基於ownProps,因此須要根據dependsOnOwnProps屬性來檢查,判斷是否須要調用方法進行更新。2) ownProps做爲mergeProps的一個必要參數,因此不須要作任何判斷,mergePorps必須被調用
當Redux Store, OwnProps都發生了改變
綜合以前的兩點,mapStateToProps必須調用,mapDispatchToProps根據dependsOnOwnProps屬性調用,mergeProps必須調用
在connect定義的時候,通常儘可能使用pure:true的狀況(默認值),由於在這種狀況下,會對props進行差異檢查。若是沒有改變,就不會去調用connectAdvanced組件去更新。若是內部組件同時根據 除 父組件傳入的props和Redux store的其餘狀態進行更新渲染,那麼pure必須是false。
option中的areStatesEqual(默認值爲===),areOwnPropsEqual(默認值爲shallowEqual), areStatePropsEqual(默認值爲shallowEqual), areMergedPropsEqual(默認值爲shallowEqual),能夠根據須要來修改這幾個參數,當pure爲true的時候,檢查更多沒必要要的re-render