0

我有一个呈现文件列表的 React 组件。有时列表很长,并且在这种情况下,从 UI 角度来看,分页并不理想,因此文件列表在重新渲染期间变得非常慢(例如,在拖放文件以重新排序时)。

导致缓慢的一件事是,在为每个文件运行一次的循环中,有一些bind()调用:

render() {
    return (
        <...>
        {this.props.files.map((file, index) => {
            return (
                <tr
                    key={`${index}#${file.name}`}
                    onDragStart={this.onDragStart.bind(this, file, index)}
                    onDragEnter={this.onDragEnter.bind(this, file)}
                    onDragOver={this.onDragOver.bind(this, file)}
                    onDragLeave={this.onDragLeave.bind(this, file)}
                    onDrop={this.onDrop.bind(this, file, index)}
                />
            );
        })}
        </...>
    );
}

这些绑定是必要的,因此拖放处理程序知道正在拖动哪个文件以及将其放置在哪里。由于所有这些绑定为数百个文件中的每一个运行一次(即使结果元素被优化并且从未真正被渲染),我想事情有点缓慢也就不足为奇了。

我想知道是否有更好的方法来做到这一点,以某种方式将必要的每次迭代数据传递给这些函数,而不必在每次迭代中为每个函数创建唯一的绑定。

我有一个可能的解决方案,我将把它作为我自己的答案发布,但是我希望得到反馈,了解这个解决方案是更好还是更差,以及它是否有任何缺点。

4

1 回答 1

0

所以我的解决方案是按照常规做法在构造函数中绑定函数一次,然后将每次迭代数据放在<tr/>DOM 元素本身上。

调用函数时,浏览器传递一个Event对象,该对象包含currentTarget指向附加了事件处理程序的 DOM 节点的属性,从而允许再次提取每次迭代数据。

这允许通过多次渲染一遍又一遍地使用相同的函数(在构造函数中只绑定一次),而无需额外绑定。

这种方法的唯一缺点是对象不能作为 DOM 属性附加,只能作为字符串附加。在我的情况下,我删除了file对象并坚持使用 numeric ,并仅在需要时index使用它来查找对象。file

constructor() {
    // Functions are now bound only once during construction
    this.onDragStart = this.onDragStart.bind(this);
    this.onDragEnter = this.onDragEnter.bind(this);
    this.onDragOver = this.onDragOver.bind(this);
    this.onDragLeave = this.onDragLeave.bind(this);
    this.onDrop = this.onDrop.bind(this);
}

onDragStart(event) {
    // 'index' is recovered from the DOM node
    const index = parseInt(event.currentTarget.dataset.index);
    console.log('Event with index', index);

    // Get back the 'file' object (unique to my code, but showing that
    // I could not pass an object through this method and thus had to
    // retrieve it again.)
    const file = (index >= 0) ? this.props.files[index] : null;
}
// Same for other onXXX functions

// No more binds!
render() {
    return (
        <...>
        {this.props.files.map((file, index) => {
            return (
                <tr
                    key={`${index}#${file.name}`}
                    data-index={index}
                    onDragStart={this.onDragStart}
                    onDragEnter={this.onDragEnter}
                    onDragOver={this.onDragOver}
                    onDragLeave={this.onDragLeave}
                    onDrop={this.onDrop}
                />
            );
        })}
        </...>
    );
}
于 2018-12-29T12:26:17.803 回答