在React中构建一个大型多选,而不会非常缓慢

Building a large multiselect in React without it being really slow

本文关键字:缓慢 非常 大型 一个 构建 React      更新时间:2023-09-26

我正在构建的应用程序需要大量的多选。它在用户界面中工作,因为我使用这个库,它可以让人们搜索选项,但我无法在React中在合理的时间内渲染它。

链接到JSFiddle。

我制作了一个更简单的版本,显示了相同的问题。

它包含一些设置代码,可以创建一个500项的列表。它还列出了默认情况下应选择的项目。现在我把它设置为x%1,所以默认情况下每个选项都是打开的,因为这似乎是瓶颈。我还启动了startTime变量,只是为了跟踪事情。

var list = [];
var defaultList = [];
for (var x = 0; x < 500; x += 1) {
  list.push(x);
  if (x%1 === 0) {
    defaultList.push(x)
  }
}
var startTime=new Date().getTime();

然后,我们将其传递到一个具有ReactDom.render()的组件中,该组件有一个回调来提醒在渲染后已经过了多少毫秒:

ReactDOM.render(
  <Hello
    list={list}
    defaultList={defaultList}  
  />,
  document.getElementById('container'),
  ()=>{
    alert(new Date().getTime() - startTime)
  }
);

最后,组件本身,它只对list中的所有选项进行简单的多选,并默认检查defaultList:中的所有选择

var Hello = React.createClass({
  render: function() {
    return (
        <select defaultValue={this.props.defaultList} multiple>
        {this.props.list.map(item => {
            return (<option value={item} key={item}>{item}</option>)
        })}
      </select>
    )
  }
});

在我的计算机上运行此fiddle会产生一个警报,在1000毫秒内显示以渲染此组件。如果我将默认列表的限定符从x%1更改为x%50,那么有10个选定项目,只需要76毫秒。

起初,我认为瓶颈只是构建500个option元素,但似乎速度减慢实际上是由于使用了大量默认值。

所以我想我的问题是:

  • 有人知道如何获得相同的结果以更快地渲染吗
  • 当谈到React性能时,我是否缺少一些见解
  • 为什么添加默认值会增加这么多开销

谢谢。

请注意,我意识到React在JSFiddle中的运行速度会变慢,在生产中我应该使用React的生产版本,,如果我不把我的列表列为500项,就不会花那么长时间。这些不是我想要的答案。

EDIT:看起来React可能会一次一个地将每个option标记为selected,从而导致500个重发。这也许可以解释发生了什么——这是React中的一个错误吗?我看到"强制同步布局可能是性能瓶颈。"Chrome开发工具中的警告。

您看到的是DOM的第一次渲染速度很慢。取此代码:

let html = '<select multiple>'
for (var x = 0; x < 500; x += 1) {
  html += `<option value=${x} selected>${x}</option>`
}
html += '</select>'
var startTime=new Date().getTime();
document.getElementById('container').innerHTML = html;
alert(new Date().getTime() - startTime)

jsfiddle

它在我的机器(Chrome 47,Windows 10)上执行与您的反应代码相同的代码,大约5000毫秒。

如果我使用Microsoft Edge,时间从5000ms变为231ms(react)和12ms(DOM操作)。这里的Chrome DOM速度较慢(与Edge相比),并且选项元素最终必须呈现到DOM中。更新可能会更快。

我已经编写了一些代码,这些代码也做了同样的工作,但不是<select>字段。这是一个无序的列表,列表项具有单击处理程序。性能提高了约10倍(Chrome~500ms,Edge~300ms)。

class Select extends React.Component {
  constructor (props) {
    super(props)
    this.state = {}
    this.state.selected = props.selected
  }
  handleClick () {
    this.setState({selected: !this.state.selected})
  }
  render () {
    const val = this.props.value
    const selected = this.state.selected
    return (
      <li onClick={this.handleClick.bind(this)} className={selected ? 'selected' : ''}>
        {val}
      </li>
    )
  }
}
const Hello = ({list, defaultList}) => 
  <ul>
    {list.map(item =>
      <Select key={item} value={item} selected={defaultList.indexOf(item) !== -1}/>)}
  </ul>

jsfiddle