我有一个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)}
/>
);
})}
</...>
);
}
这些绑定是必需的,因此拖放处理程序知道要拖动的文件以及将文件拖放到的位置。所有这些绑定对于数百个文件中的每个文件都运行一次(即使对结果元素进行了优化并且从未实际渲染过),我想事情有点迟钝也就不足为奇了。
我想知道是否还有更好的方法,以某种方式将必要的每次迭代数据传递给这些函数,而不必在每次迭代中为每个函数创建唯一的绑定。
我有一个可能的解决方案,将作为我自己的答案发布,但是对于该解决方案是好是坏,以及它是否有缺点,我将不胜感激。
答案 0 :(得分:0)
因此,我的解决方案是按照通常的做法在构造函数中绑定一次函数,然后将每次迭代数据放置在<tr/>
DOM元素本身上。
调用函数时,浏览器将传递一个Event
对象,该对象包含指向附加了事件处理程序的DOM节点的currentTarget
属性,从而允许再次提取每个迭代数据
这允许在多个渲染中一次又一次地使用相同的函数(在构造函数中仅绑定一次),而无需附加绑定。
此方法的唯一缺点是不能将对象附加为DOM属性,而只能附加为字符串。在我的情况下,我放下了file
对象并停留在数字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}
/>
);
})}
</...>
);
}