React performance considerations
These are some considerations to take into account when developing an application with React and Redux.
One of the most common performance failures in React is the unnecessary rendering of components. A library that can be very useful to detect this is why-did-you-update. Notifies you in the console when potentially unnecessary re-renders occur, super helpful for easy perf gains.
Another handy tool to measure performance is react-addons-perf.
Also remember to use shouldComponentUpdate()
method in statefull components to check that the props of a component didn’t change and skip rendering (React by default render the component). We can use PureComponent
instead of Component
. This would compare all props using strict equality (===)
and rerender only if any of the props change. If you want to achieve the same behavior but in a functional component I recommend you use recompose
. Specifically the pure
HOC. You can find how to use it here.
If you’re using Redux then connected components are already pure.
Just remember that if only one of the props change, then the connected component rerenders — this includes all its children, too. So even if you use Redux for page components, you should use pure
or shouldUpdate
for components further down in the render tree.
Also, beware that Redux does the props comparison using strict equality. Since Redux connects the state to a component’s props, if you mutate an object in the state, Redux props comparison will miss it. That’s why you must use immutability in your reducers.
To prevent useless renders in (Redux) connected components, you must also make sure that the mapStateToProps
function doesn’t return new objects each time it is called. Reselect solves this problem by using memoization. Instead of computing the props directly in mapStateToProps, you use a selector from reselect, which returns the same output if the input didn’t change.
JSX
Take care of Object Literals
import React from 'react';
import MyTableComponent from './MyTableComponent';
const Datagrid = (props) => (
<MyTableComponent style={{ marginTop: 10 }}>
...
</MyTableComponent>
)
The style
prop of the <MyTableComponent>
component gets a new value every time the <Datagrid>
component is rendered. So even if <MyTableComponent>
is pure, it will be rendered every time <Datagrid>
is rendered. In fact, each time you pass an object literal as prop to a child component, you break purity. The solution is simple:
import React from 'react';
import MyTableComponent from './MyTableComponent';
const tableStyle = { marginTop: 10 };
const Datagrid = (props) => (
<MyTableComponent style={tableStyle}>
...
</MyTableComponent>
)
Functions
// NEVER do this
render() {
return <MyInput onChange={this.props.update.bind(this)} />;
}
// NEVER do this
render() {
return <MyInput onChange={() => this.props.update()} />;
}
// Instead do this
onChange() {
this.props.doUpdate()
}
render() {
return <MyInput onChange={this.onChange}/>;
}
Arrays
// NEVER do this, if there are no items, SubComponent will render every time!
render() {
return <SubComponent items={this.props.items || []}/>
}
// This will avoid re-rendering
const EMPTY_ARRAY = []
render() {
return <SubComponent items={this.props.items || EMPTY_ARRAY}/>
}