If you implement table or list of your own, this simple tip will gain some performance improvement and can save a lot of rerenders.
Consider we have a Table and TableRow component which we use to show large Tabular data which has checkboxes used by users to select the rows.
// data source
const users = [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'},
{id: 4, name: 'D'},
];
class Table extends React.Component {
constructor() {
super();
this.state = {
selected: {},
}
}
handleSelect = (e) => {
const selected = this.state.selected;
selected[e.target.name] = e.target.checked;
this.setState({ selected });
}
render() {
return (
<table>
<thead>
<tr>
<th />
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{
users.map((user) => {
return (
<TableRow
key={user.id}
id={user.id}
name={user.name}
selected={this.state.selected[user.id]}
handleSelect={this.handleSelect}
/>;
);
})
}
</tbody>
</table>
);
}
}
And the TableRow component
const TableRow = ({ selected, id, name, handleSelect }) => {
console.log(`render TableRow :: ${id} :: ${name}`);
return (
<tr>
<td>
<input
name={id}
type="checkbox"
checked={selected}
onChange={handleSelect}
/>
</td>
<td>{id}</td>
<td>{name}</td>
</tr>
);
}
TableRow.defaultProps = {
selected: false
}
The TableRow component have a console.log which will log the id & name when ever the component renders. This will help us to know which all rows are getting rerendered.
Now when the user select one of row, all the rows get rerendered in the above example. You can see console.log for all the items in the data source.

You can see the live version in jsbin
In the above demo we have only 4 items and 3 columns, which didn’t cause much performance degradation. Where as consider the above table with around 200 items and 50 columns?
A simple checkbox selection will trigger 200 rerenders for TableRow component.
Using PureComponent
The simple and effective optimisation we can do here is convert the TableRow component to a PureComponent.
class TableRow extends React.PureComponent {
defaultProps = {
selected: false
}
render() {
const { selected, id, name, handleSelect } = this.props;
console.log(`render TableRow :: ${id} :: ${name}`);
return (
<tr>
<td>
<input
name={id}
type="checkbox"
checked={selected}
onChange={handleSelect}
/>
</td>
<td>{id}</td>
<td>{name}</td>
</tr>
);
}
}
Now lets try selecting one of the row and see the improvement.

Now when we select a row, only that row rerenders. PureComponent has implemented
shouldComponentUpdate which does a shallow compare of props and do rerenders only if it differs.
You can see the live version in jsbin
In the demo, the using of PureComponent was possible because the props where number & string. If the props are Array or Object we won’t be
able to use PureComponent since the shallow compare of PureComponent might lead to false positives.
In such cases we can implement write our own parent component which implements deep compare in shouldComponentUpdate.
class PerfComponent extends Component {
shouldComponentUpdate(nextProps) {
// implement/ use deep compare functionality
if(!deepEqual) {
return true;
}
return false;
}
}
export default PerfComponent;
and inherit TableRow from PerfComponent.
class TableRow extends PerfComponent {
defaultProps = {
selected: false
}
render() {
const { selected, user, handleSelect } = this.props;
console.log(`render TableRow :: ${user.id} :: ${user.name}`);
return (
<tr>
<td>
<input
name={user.id}
type="checkbox"
checked={selected}
onChange={handleSelect}
/>
</td>
<td>{user.id}</td>
<td>{user.name}</td>
</tr>
);
}
}
Hope it helped.
Versions of Language/packages used in this post.
| Library/Language | Version |
| ---------------- |---------|
| React | 16.4.0 |