Avoid unnecessary setState call when Route receives same props.
See original GitHub issueI just encounter a situation. I have the below App
component connected to Redux. The requestQuantity
changes according to current processing XHRs , which causes the App re-render.
Then the TopicList
will re-render which shouldn’t happen. The TopicList
is also connected to Redux and doesn’t depend on requestQuantity
, based on the shallow comparison of Redux’s connect, changing of requestQuantity
has nothing to do with the TopicList
’s render.
class App extends Component {
render() {
const { requestQuantity } = this.props;
return (
<div>
<Router>
<Switch>
<Route exact path="/" component={TopicList} />
<Route path="/login" component={Login} />
<Route path="/topics" component={TopicList} />
</Switch>
</Router>
{requestQuantity > 0 && <Loading />}
</div>
);
}
}
const mapStateToProps = (state, props) => {
return {
requestQuantity: getRequestQuantity(state)
};
};
export default connect(mapStateToProps)(App);
I check the source code and find the Route’s componentWillReceiveProps
will always call the setState
, which set a new match object. It is the new match prop passed to the TopicList
causing the Redux’s shallow comparison failed.
I think we can make some comparison before calling the setState
. If the location
, strict
, exact
and sensitive
don’t change, we can skip the setState
and just passing the old state to
the components in Route
. In this way , the components can render more efficiently especially when using with Redux and Mobx.
componentWillReceiveProps(nextProps, nextContext) {
warning(
!(nextProps.location && !this.props.location),
'<Route> elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'
)
warning(
!(!nextProps.location && this.props.location),
'<Route> elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.'
)
// do some shouldComputeMatch logic before setState
this.setState({
match: this.computeMatch(nextProps, nextContext.router)
})
}
Issue Analytics
- State:
- Created 6 years ago
- Comments:5 (3 by maintainers)
@johnnyreilly aha, you’re right, the workaround is by me.
There’s a workaround here: https://stackoverflow.com/questions/47375973/react-router-causes-redux-container-components-re-render-unneccessary (perhaps by original poster?)
It would be great to know if this is considered “safe”: