React点击事件后交互时间很高该怎么优化?
我正在做一个待办事项列表,点击按钮会动态渲染1000条数据。发现每次点击后交互时间(Time to Interactive)显示有2-3秒延迟,页面明显卡顿。我用了PureComponent和shouldComponentUpdate,但效果不明显。
代码结构大概是这样的:
class TodoList extends React.PureComponent {
state = { items: [] };
handleClick = () => {
const newItems = Array.from({length: 1000}, (_, i) => `Item ${i}`);
this.setState({ items: newItems });
};
render() {
return (
<>
<button onClick={this.handleClick}>加载数据</button>
<ul>
{this.state.items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</>
);
}
}
测试发现列表渲染时内存占用飙升,但状态更新逻辑应该没问题啊。是不是key设置有问题?或者有其他优化点没考虑到?
你的直觉对了一半,key用index在这个场景下其实不是主要问题,因为你是整体替换数据,不是增删改。真正的问题是React要一次性创建1000个真实的DOM节点并插入页面,这个操作本身就很耗时间。
我给你几个实用的优化方案。
第一个方案是用虚拟列表,只渲染可视区域内的元素。这是最彻底的解决办法,推荐用react-window这个库。
第二个方案如果你不想引入新库,可以用时间分片,把渲染任务拆成多批执行。用requestIdleCallback或者setTimeout都行。
还有一个细节,你现在的写法每次点击都会生成新的数组,如果连续点击可能会有问题。可以加个loading状态防止重复点击。
虚拟列表是最推荐的方案,渲染10000条都没压力。时间分片那个方案会有渐进式渲染的效果,用户体验上可能稍微好一点,但总耗时其实差不多。
另外你提到内存占用飙升,这个正常,1000个DOM节点本来就要占内存,虚拟列表能完美解决这个问题,因为永远只渲染屏幕可见的那几十个。
PureComponent和shouldComponentUpdate,但这里还有几个优化点可以试试。### 1. **key 的问题**
你的
key是用索引index设置的,这在动态列表场景下是不推荐的。React 官方文档里明确提到,如果列表项顺序会变或者有增删操作,用索引会导致不必要的重渲染。你可以把每条数据的唯一标识作为key,比如这样:然后在渲染时用
id作为key:这样更清晰,也避免了索引带来的性能问题。
---
### 2. **虚拟化列表**
渲染 1000 条数据对浏览器来说负担确实有点大。即使用户看不到那么多内容,React 还是会尝试渲染所有的 DOM 节点,导致内存占用飙升和卡顿。建议你用虚拟化列表(virtualized list),只渲染当前视口内的数据。
可以用现成的库,比如
react-window或者react-virtualized。简单举个例子,用react-window的话:这样就只渲染视口内的数据,滚动时动态更新,性能提升非常明显。
---
### 3. **setState 的批量处理**
虽然这里看起来不是主要问题,但还是提一下:
setState是异步的,如果需要频繁更新状态,可以考虑合并多次调用,减少渲染次数。不过你这个例子中一次更新 1000 条数据,应该没问题。---
总结一下,
key改为唯一标识,加上虚拟化列表,性能基本就能搞定。别看虚拟化简单,渲染大量数据的时候真香。希望这些改动对你有帮助!