Sunday, May 19, 2024
 Popular · Latest · Hot · Upcoming
69
rated 0 times [  75] [ 6]  / answers: 1 / hits: 15795  / 10 Years ago, wed, january 14, 2015, 12:00:00

I was really disappointed by the performance I got on the following simple ReactJS example. When clicking on an item, the label (count) gets updated accordingly. Unfortunately, this takes roughly ~0.5-1 second to get updated. That's mainly due to re-rendering the entire todo list.



My understanding is that React's key design decision is to make the API seem like it re-renders the whole app on every update. It is supposed take the current state of the DOM and compare it with the target DOM representation, do a diff and update only the things that need to get updated.



Am I doing something which is not optimal? I could always update the count label manually (and the state silently) and that will be an almost instant operation but that takes away the point of using ReactJS.





/** @jsx React.DOM */

TodoItem = React.createClass({

getDefaultProps: function () {
return {
completedCallback: function () {
console.log('not callback provided');
}
};
},
getInitialState: function () {
return this.props;
},

updateCompletedState: function () {
var isCompleted = !this.state.data.completed;
this.setState(_.extend(this.state.data, {
completed: isCompleted
}));
this.props.completedCallback(isCompleted);
},

render: function () {
var renderContext = this.state.data ?
(<li className={'todo-item' + (this.state.data.completed ? ' ' + 'strike-through' : '')}>
<input onClick={this.updateCompletedState} type=checkbox checked={this.state.data.completed ? 'checked' : ''} />
<span onClick={this.updateCompletedState} className=description>{this.state.data.description}</span>
</li>) : null;

return renderContext;
}
});


var TodoList = React.createClass({
getInitialState: function () {
return {
todoItems: this.props.data.todoItems,
completedTodoItemsCount: 0
};
},

updateCount: function (isCompleted) {
this.setState(_.extend(this.state, {
completedTodoItemsCount: isCompleted ? this.state.completedTodoItemsCount + 1 : this.state.completedTodoItemsCount - 1
}));
},

render: function () {
var updateCount = this.updateCount;
return (
<div>
<div>count: {this.state.completedTodoItemsCount}</div>
<ul className=todo-list>
{ this.state.todoItems.map(function (todoItem) {
return <TodoItem data={ todoItem } completedCallback={ updateCount } />
}) }
</ul>
</div>
);
}
});

var data = {todoItems: []}, i = 0;

while(i++ < 1000) {
data.todoItems.push({description: 'Comment ' + i, completed: false});
}

React.renderComponent(<TodoList data={ data } />, document.body);

<script src=http://fb.me/react-js-fiddle-integration.js></script>





jsFiddle link, just in case: http://jsfiddle.net/9nrnz1qm/3/


More From » performance

 Answers
10

If you do the following, you can cut the time down by a lot. It spends 25ms to 45ms to update for me.




  • use the production build

  • implement shouldComponentUpdate

  • update the state immutably



updateCompletedState: function (event) {
var isCompleted = event.target.checked;
this.setState({data:
_.extend({}, this.state.data, {
completed: isCompleted
})
});
this.props.completedCallback(isCompleted);
},

shouldComponentUpdate: function(nextProps, nextState){
return nextState.data.completed !== this.state.data.completed;
},


Updated fiddle



(there are a lot of questionable things about this code, daniula points out some of them)


[#68203] Tuesday, January 13, 2015, 10 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
ramiro

Total Points: 431
Total Questions: 96
Total Answers: 105

Location: Northern Ireland
Member since Mon, Nov 14, 2022
2 Years ago
;