I need to draw a big table, not really big, about 400x400 cells. But React renders it too slow, and on every click on the cell, cell should be updated and this update takes same huge amount of time. Any suggestions how to speed it up ? Or React is just not suitable tool for such task ?
Here is example (with slightly reduced size of table): /
var ROWSC = 400;
var COLSC = 100;
var Hello = React.createClass({
getInitialState: function () {
return {
t: { "1-1": 'c' }
};
},
clicked: function (k) {
var t = this.state.t;
t[k] = t[k] ? 0 : 'c';
this.setState({ t: t });
},
render: function() {
var items = [];
for (var r = 0; r < ROWSC; r++) {
var cols = [];
for (var c = 0; c < COLSC; c++) {
var k = ''+r+'-'+c;
cols.push(<td key={c} onClick={this.clicked.bind(this,k)} className={this.state.t[k]}> </td>);
}
items.push(<tr key={r}>{cols}</tr>);
}
return <table>
{items}
</table>
</div>;
}
});
React.render(<Hello name="World" />, document.getElementById('container'));
I need to draw a big table, not really big, about 400x400 cells. But React renders it too slow, and on every click on the cell, cell should be updated and this update takes same huge amount of time. Any suggestions how to speed it up ? Or React is just not suitable tool for such task ?
Here is example (with slightly reduced size of table): https://jsfiddle/69z2wepo/15731/
var ROWSC = 400;
var COLSC = 100;
var Hello = React.createClass({
getInitialState: function () {
return {
t: { "1-1": 'c' }
};
},
clicked: function (k) {
var t = this.state.t;
t[k] = t[k] ? 0 : 'c';
this.setState({ t: t });
},
render: function() {
var items = [];
for (var r = 0; r < ROWSC; r++) {
var cols = [];
for (var c = 0; c < COLSC; c++) {
var k = ''+r+'-'+c;
cols.push(<td key={c} onClick={this.clicked.bind(this,k)} className={this.state.t[k]}> </td>);
}
items.push(<tr key={r}>{cols}</tr>);
}
return <table>
{items}
</table>
</div>;
}
});
React.render(<Hello name="World" />, document.getElementById('container'));
Share
Improve this question
asked Sep 11, 2015 at 19:34
DfrDfr
4,18510 gold badges45 silver badges66 bronze badges
1
- 1 Well you can see that this is O(n^2), 400*100 is not so big but it still is. If you decrease it on 50*50 you'll immediately see the difference. There is an interesting speed parison at this link but still react beats the other stuff:codementor.io/reactjs/tutorial/… – EugenSunic Commented Sep 11, 2015 at 19:56
3 Answers
Reset to default 2By default, React re-renders everything, but in the presence of performance problems,
it is possible to use the shouldComponentUpdate
function to determine which parts
of the ponent tree to exclude on updates.
In your example, there is only a single row that can be updated at once, so if we start tracking which row the update occured on we can make sure only this row is updated. First, we must introduce a new ponent that wraps the table row where we can place our hook.
var Row = React.createClass({
shouldComponentUpdate: function(nextProps) {
return nextProps.mustUpdate;
},
render: function() {
return <tr>{this.props.children}</tr>;
}
});
Then we can use it like
items.push(
<Row key={r}
mustUpdate={this.state.lastUpdatedRow === r}>
{cols}
</Row>);
Furthermore, it seems like a waste to re-render all those cells too, so we can introduce yet another ponent that wraps the table cells.
var Cell = React.createClass({
shouldComponentUpdate: function(nextProps) {
return this.props.selected !== nextProps.selected;
},
render: function() {
var props = this.props;
return (
<td onClick={props.onClick.bind(null, props.col, props.row)}
className={props.selected ? 'c' : ''}>
</td>
);
}
});
This should give you a significant performance improvement on updates. If it is still not good enough for your particular problem, it might be that React is not ideal for your use case. Anyway, that is the essence of optimizing React programs, you split ponents into smaller ponents and make sure only the parts that actually changed update.
While I was reviewing your results in the console, I noticed the following popped up on each jsfiddle run:
You are using the in-browser JSX transformer. Be sure to prepile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx
I followed the link and saw that the documentation warns about performance impacts when using the in-browser JSX transformer:
The in-browser JSX transformer is fairly large and results in extraneous putation client-side that can be avoided. Do not use it in production
Perhaps doing another test with JSX prepilation would give you a better idea about whether this is a good use case for React.
Two things:
Make sure to prepile JSX to avoid that slowness. (In the jsfiddle, you'll see a console warning "You are using the in-browser JSX transformer. Be sure to prepile your JSX for production".
Being implemented as a single Component with click setting state on itself, causes the ponent to have to re-process the entire table (because setState
triggers render
which rebuilds the table DOM). You can avoid much of this by creating a Component to represent each table cell. Then in your clicked
function, instead of calling setState on Hello
, just call setState
on the cell that was clicked. That way only the cell that changed will re-render.
This doesn't help the initial render, but it will significantly speed up UI updates due to clicks.