React点击事件后交互时间很高该怎么优化?

建利 阅读 19

我正在做一个待办事项列表,点击按钮会动态渲染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设置有问题?或者有其他优化点没考虑到?

我来解答 赞 5 收藏
二维码
手机扫码查看
1 条解答
Mc.馨然
Mc.馨然 Lv1
你这个问题挺典型的,动态渲染大量数据时确实容易出现性能问题。虽然用了 PureComponentshouldComponentUpdate,但这里还有几个优化点可以试试。

### 1. **key 的问题**
你的 key 是用索引 index 设置的,这在动态列表场景下是不推荐的。React 官方文档里明确提到,如果列表项顺序会变或者有增删操作,用索引会导致不必要的重渲染。你可以把每条数据的唯一标识作为 key,比如这样:

const newItems = Array.from({length: 1000}, (_, i) => ({ id: item-${i}, name: Item ${i} }));


然后在渲染时用 id 作为 key

{this.state.items.map(item => (
  • {item.name}

  • ))}


    这样更清晰,也避免了索引带来的性能问题。

    ---

    ### 2. **虚拟化列表**
    渲染 1000 条数据对浏览器来说负担确实有点大。即使用户看不到那么多内容,React 还是会尝试渲染所有的 DOM 节点,导致内存占用飙升和卡顿。建议你用虚拟化列表(virtualized list),只渲染当前视口内的数据。

    可以用现成的库,比如 react-window 或者 react-virtualized。简单举个例子,用 react-window 的话:

    import { FixedSizeList as List } from 'react-window';

    class TodoList extends React.PureComponent {
    state = { items: [] };

    handleClick = () => {
    const newItems = Array.from({ length: 1000 }, (_, i) => ({ id: item-${i}, name: Item ${i} }));
    this.setState({ items: newItems });
    };

    renderRow = ({ index, style }) => {
    const item = this.state.items[index];
    return (

    {item.name}

    );
    };

    render() {
    return (
    <>
    <button onClick={this.handleClick}>加载数据</button>
    <List
    height={400}
    width={300}
    itemCount={this.state.items.length}
    itemSize={35}
    >
    {this.renderRow}
    </List>
    </>
    );
    }
    }


    这样就只渲染视口内的数据,滚动时动态更新,性能提升非常明显。

    ---

    ### 3. **setState 的批量处理**
    虽然这里看起来不是主要问题,但还是提一下:setState 是异步的,如果需要频繁更新状态,可以考虑合并多次调用,减少渲染次数。不过你这个例子中一次更新 1000 条数据,应该没问题。

    ---

    总结一下,key 改为唯一标识,加上虚拟化列表,性能基本就能搞定。别看虚拟化简单,渲染大量数据的时候真香。希望这些改动对你有帮助!
    点赞 9
    2026-02-01 17:08