Last active
July 12, 2017 15:23
-
-
Save hkjpotato/d9b9de0476255d638007b5887f23f194 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
//1. it is stateful because it knows whether the React Component should update | |
function makeSelectorStateful(selector, store) { | |
// wrap the selector in an object that tracks its results between runs. | |
const statefulSelector = { | |
run: function (props) { | |
const nextProps = selector(store.getState(), props); | |
//but it set shouldComponentUpdate to true if it is a different from previous one | |
if (nextProps !== statefulSelector.props) { | |
//update info for React | |
statefulSelector.shouldComponentUpdate = true; | |
statefulSelector.props = nextProps; | |
} | |
} | |
} | |
return statefulSelector | |
} | |
function connectHOC(mapStateToProps, mapDispatchToProps) { | |
return function wrapWithConnect(WrappedComponent) { | |
class Connect extends React.Component { | |
constructor(props, context) { | |
super(props, context) | |
this.store = context.store //access store from context | |
this.initSelector() | |
//...subscrition | |
} | |
initSelector() { | |
const selector = selectorFactory(this.store.dispatch, mapStateToProps, mapDispatchToProps) | |
this.selector = makeSelectorStateful(selector, this.store) | |
//init the mergedProp for initial render | |
this.selector.run(this.props) | |
} | |
//data source 1: store state change | |
onStateChange() { | |
this.selector.run(this.props) | |
if (!this.selector.shouldComponentUpdate) { | |
//if it does not get re-render, we still need to notify the nested subscription | |
this.subscription.notifyNestedSubs() | |
} else { | |
this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdate | |
this.setState({}) | |
} | |
} | |
notifyNestedSubsOnComponentDidUpdate() { | |
this.componentDidUpdate = undefined; //unimplement it to avoid notification due to normal update(e.g. parent's re-render) | |
this.subscription.notifyNestedSubs(); | |
} | |
//data source 2: ownProps change | |
componentWillReceiveProps(nextProps) { | |
//run the stateful selector to update mergedProps | |
this.selector.run(nextProps) | |
} | |
shouldComponentUpdate() { | |
//rely on the stateful selector, prevent unecessary re-render | |
return this.selector.shouldComponentUpdate | |
} | |
render() { | |
const selector = this.selector | |
selector.shouldComponentUpdate = false //reset the flag of the selector | |
return React.createElement(WrappedComponent, selector.props) //get the mergedProps from the selector | |
} | |
} | |
//.... | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment