Javascript ReactJS。渲染和更新1500个简单列表时速度非常慢<;李>;元素。我觉得VirtualDOM很快

Javascript ReactJS。渲染和更新1500个简单列表时速度非常慢<;李>;元素。我觉得VirtualDOM很快,javascript,performance,dom,reactjs,Javascript,Performance,Dom,Reactjs,我对下面这个简单的例子的性能感到非常失望。单击项目时,标签(计数)会相应更新。不幸的是,这大约需要0.5-1秒才能得到更新。这主要是因为“重新呈现”了整个待办事项列表 我的理解是React的关键设计决策是让API看起来像是每次更新都会重新呈现整个应用程序。它应该获取DOM的当前状态,并将其与目标DOM表示进行比较,进行区分并仅更新需要更新的内容 我是否在做一些非最佳的事情?我总是可以手动更新计数标签(并以静默方式更新状态),这几乎是一个即时操作,但这就失去了使用ReactJS的意义 /**@j

我对下面这个简单的例子的性能感到非常失望。单击项目时,标签(计数)会相应更新。不幸的是,这大约需要0.5-1秒才能得到更新。这主要是因为“重新呈现”了整个待办事项列表

我的理解是React的关键设计决策是让API看起来像是每次更新都会重新呈现整个应用程序。它应该获取DOM的当前状态,并将其与目标DOM表示进行比较,进行区分并仅更新需要更新的内容

我是否在做一些非最佳的事情?我总是可以手动更新计数标签(并以静默方式更新状态),这几乎是一个即时操作,但这就失去了使用ReactJS的意义

/**@jsx React.DOM*/
TodoItem=React.createClass({
getDefaultProps:函数(){
返回{
completedCallback:函数(){
log(“未提供回调”);
}
};
},
getInitialState:函数(){
归还这个道具;
},
updateCompletedState:函数(){
var isCompleted=!this.state.data.completed;
this.setState(u.extend)(this.state.data{
已完成:已完成
}));
this.props.completedCallback(isCompleted);
},
渲染:函数(){
var renderContext=this.state.data?
(
  • {this.state.data.description}
  • ):空; 返回renderContext; } }); var TodoList=React.createClass({ getInitialState:函数(){ 返回{ todoItems:this.props.data.todoItems, 已完成的待办事项:0 }; }, updateCount:函数(已完成){ this.setState(u.extend)(this.state{ CompletedToDoitemScunt:isCompleted?this.state.CompletedToDoitemScunt+1:this.state.CompletedToDoitemScunt-1 })); }, 渲染:函数(){ var updateCount=this.updateCount; 返回( 计数:{this.state.completedToDoItemsCunt}
      {this.state.todoItems.map(函数(todoItem)){ 返回 }) }
    ); } }); var data={todoItems:[]},i=0; 而(i++<1000){ push({description:'Comment'+i,completed:false}); } React.renderComponent(,document.body)
  • 当您生成元素列表时,您应该为每个人提供唯一的关键道具。就你而言:

    <ul className="todo-list">
        { this.state.todoItems.map(function (todoItem, i) {
            return <TodoItem key={i} data={ todoItem } completedCallback={ updateCount } />
        }) }
    </ul>
    
  • 您正在进行一些字符串连接以设置正确的
    类名
    。要获得更具可读性的代码,请尝试使用nice和simple:

    render:function(){
    var renderContext=this.state.data?
    var cx=React.addons.classSet({
    “待办事项”:true,
    “穿透”:this.state.data.completed
    });
    (
  • {this.state.data.description}
  • ):空; 返回renderContext; }

  • 如果你做到以下几点,你可以大大缩短时间。它花了25到45毫秒为我更新

    • 使用生产构建
    • 实现shouldComponentUpdate
    • 不可变地更新状态
    updateCompletedState:函数(事件){
    var isCompleted=event.target.checked;
    此.setState({数据:
    _.extend({},this.state.data{
    已完成:已完成
    })
    });
    this.props.completedCallback(isCompleted);
    },
    shouldComponentUpdate:函数(nextProps,nextState){
    返回nextState.data.completed!==this.state.data.completed;
    },
    


    (daniula指出,这段代码有很多值得怀疑的地方)

    我正在查看列表的呈现位置()

    <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>
    
    然后,只需在更改后重新提交一个TodoItem,如下所示:

    ReactDOM.render(<TodoItem ...>, document.getElementById('someindex'));
    
    ReactDOM.render(,document.getElementById('someindex');
    

    ReactJS应该是快速的,是的,但是您仍然需要坚持通用编程范式,即要求机器尽可能少地执行操作,从而尽可能快地生成结果。重新渲染那些不需要重新渲染的内容会阻碍这一点,无论这是否是“最佳实践”。

    我在制作版本中得到了0.13秒。区分4500个元素需要一些时间。这里唯一好的解决方案是不渲染1500个TodoItems,而最多只能看到100个:-)如何检查性能(即获得0.13秒)?我在开发工具中使用了探查器。它向您显示所有JS执行的时间线(确保它处于图表模式,而不是繁重或树形)。单击复选框后,代码执行时间约为130ms。看我的答案,它实际上下降了不少。是的。。我的是150-170msSo,这实际上意味着当TodoList被“重新渲染”时,如果TodoItem的状态不变,它将不会被“重新渲染”?正确。这意味着react不需要调用TodoItem的render,也不需要在父级更新时区分li、input和span。这意味着如果TodoItem有多个状态,即完成、部分完成等,并且应用了不同的样式,则必须检查shouldComponentUpdate函数中的所有状态。这不正是React自动检查的理想选择吗?是的,或者如果下一个状态和当前状态存在对象,您可以做一个粗略的比较。React提供了一种实现这种shouldComponentUpdate的方法,但它在默认情况下并没有启用,并且它对props和state进行了粗略的比较
    <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>
    
    return <div id={someindex++}><TodoItem
      data={ todoItem }
      completedCallback={ updateCount }
    /></div>
    
    ReactDOM.render(<TodoItem ...>, document.getElementById('someindex'));