Created
July 11, 2017 23:26
-
-
Save hkjpotato/32bc845cec58e603fd73e385e3509df7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//a factory function that return selector based on the mapping function and store.dispatch method | |
//the return selector can then use the mapping function to convert the nextState and ownProps to the mergedProps | |
function selectorFactory(dispatch, mapStateToProps, mapDispatchToProps) { | |
//cache the DIRECT INPUT for the selector | |
//the store state | |
let state | |
//the container's own props | |
let ownProps | |
//cache the itermediate results from mapping functions | |
//the derived props from the state | |
let stateProps | |
//cache the derived props from the store.dispatch | |
let dispatchProps | |
//cache the output | |
//the return merged props(stateProps + dispatchProps + ownProps) to be injected to wrappedComponent | |
let mergedProps | |
// the source selector is memorizable. | |
return function selector(nextState, nextOwnProps) { | |
//before running the actual mapping function, compare its arguments with the previous one | |
const propsChanged = !shallowEqual(nextOwnProps, ownProps) | |
const stateChanged = !strictEqual(nextState, state) | |
state = nextState | |
ownProps = nextOwnProps | |
//calculate the return mergedProps based on different scenarios | |
//to MINIMIZE the call to actual functions that calculate the result (mapping functions & mergeProps) | |
//notice: the mapping function itself can be optimized by Reselect, but it is not the concern here | |
//case 1: both state in redux and own props change | |
if (propsChanged && stateChanged) { | |
//derive new props based on state | |
stateProps = mapStateToProps(state, ownProps) | |
//since the ownProps change, update dispatch callback if it depends on props | |
if (mapDispatchToProps.length !== 1) dispatchProps = mapDispatchToProps(dispatch, ownProps) | |
//merge the props | |
mergedProps = mergeProps(stateProps, dispatchProps, ownProps) | |
return mergedProps | |
} | |
//case 2: only own props changes | |
if (propsChanged) { | |
//only update stateProps and dispatchProps if they rely on ownProps | |
if (mapStateToProps.length !== 1) stateProps = mapStateToProps(state, ownProps) //it just call the mapping function | |
if (mapDispatchToProps.length !== 1) dispatchProps = mapDispatchToProps(dispatch, ownProps) | |
mergedProps = mergeProps(stateProps, dispatchProps, ownProps) | |
return mergedProps | |
} | |
//case 3: only store state changes | |
// 1.since stateProps depends on state so must run mapStateToProps again | |
// 2.for dispatch, since store.dispatch and ownProps remain the same, no need to update | |
if (stateChanged) { | |
const nextStateProps = mapStateToProps(state, ownProps) | |
const statePropsChanged = !shallowEqual(nextStateProps, stateProps) | |
stateProps = nextStateProps | |
//if stateProps changed, update mergedProps by calling the mergeProps function | |
if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) | |
return mergedProps | |
} | |
//case 4: no change, return the cached result if no change in input | |
return mergedProps; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment