Chrome has many tools that let us know what we're doing.
First off, don't check Hide Violations. Violations are bad, let's not do them.
They may happen when first-time-loading large datasets, that's okay - but in normal, we-have-almost-everything-cached state, they shouldn't happen.
Use the Performance tab to see where time is spent, including React rendering:
Get to know the tools. They're good.
In short:
- Only use
React.PureComponent
, always - For connected components, use reselect (createStructuredSelector, createSelector) in
mapStateToProps
(grep the codebase for examples) - Avoid
[]
or{}
inmapStateToProps
, do this instead:
const emptyObj = {};
const emptyArr = [];
export default connect(SomeComponent, {
state: createStructuredSelector({
// Don't do this!
baadValue: (state) => ((state.a || {}).b || [])[0];
// Do this instead:
goodValue: (state) => ((state.a || emptyObj).b || emptyArr)[0];
}),
})
- Anonymous functions or
this.something.bind(this)
create a new value every time, and will wreckshouldComponentUpdate
.
export BadComponent extends React.PureComponent<any, any> {
doStuff () {
// stuff.
}
render () {
// Don't! This generates a different closure for each render call
return <div onClick={() => this.doStuff()}/>
// Don't either! This also generates a different function on every render
return <div onClick={this.doStuff.bind(this)}/>
}
}
// Do this!
export GoodComponent extends React.PureComponent<any, any> {
// In TypeScript, this is called an instance function
doStuff = () => {
// stuff.
}
render () {
// `this.doStuff` stays the same, won't trigger unnecessary renders
return <div onClick={this.doStuff}/>
}
}
More details in this medium article