Skip to content

Instantly share code, notes, and snippets.

@hkjpotato
Created July 11, 2017 23:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hkjpotato/32bc845cec58e603fd73e385e3509df7 to your computer and use it in GitHub Desktop.
Save hkjpotato/32bc845cec58e603fd73e385e3509df7 to your computer and use it in GitHub Desktop.
//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