title: ReactJS. Quite slow when rendering and updating a simple list of 1500 <li> elements. I thought VirtualDOM was fast
body: <p>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.</p>
  
  <p>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. </p>
  
  <p>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.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>/** @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 ?
              (&lt;li className={'todo-item' + (this.state.data.completed ? ' ' + 'strike-through' : '')}&gt;
                  &lt;input onClick={this.updateCompletedState} type="checkbox" checked={this.state.data.completed ? 'checked' : ''} /&gt;
                  &lt;span onClick={this.updateCompletedState} className="description"&gt;{this.state.data.description}&lt;/span&gt;
              &lt;/li&gt;) : 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 (
              &lt;div&gt;
                  &lt;div&gt;count: {this.state.completedTodoItemsCount}&lt;/div&gt;
                  &lt;ul className="todo-list"&gt;
                      { this.state.todoItems.map(function (todoItem) {
                          return &lt;TodoItem data={ todoItem } completedCallback={ updateCount } /&gt;
                      }) }
                  &lt;/ul&gt;
              &lt;/div&gt;
          );
      }
  });
  
  var data = {todoItems: []}, i = 0;
  
  while(i++ &lt; 1000) {
   data.todoItems.push({description: 'Comment ' + i, completed: false});
  }
  
  React.renderComponent(&lt;TodoList data={ data } /&gt;, document.body);</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="http://fb.me/react-js-fiddle-integration.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p><sub>jsFiddle link, just in case: <a href="http://jsfiddle.net/9nrnz1qm/3/" rel="noreferrer">http://jsfiddle.net/9nrnz1qm/3/</a></sub></p>