react虚拟列表怎么实现
实现虚拟列表的核心思路
虚拟列表通过仅渲染可视区域内的元素来优化长列表性能。核心原理是计算可视区域起始和结束索引,动态渲染对应数据项,并通过占位元素保持滚动条高度。
计算可视区域范围
监听滚动事件,根据滚动位置计算当前可视区域的起始索引和结束索引。需要以下关键参数:
- 容器高度(containerHeight)
- 单个项目高度(itemHeight)
- 总数据量(totalItems)
- 滚动位置(scrollTop)
可视区域索引计算公式: $$ startIndex = Math.floor(scrollTop / itemHeight) $$ $$ endIndex = Math.min( startIndex + Math.ceil(containerHeight / itemHeight), totalItems - 1 ) $$
动态渲染可见项
根据计算得到的startIndex和endIndex,从完整数据中切片出需要渲染的部分:
const visibleItems = data.slice(startIndex, endIndex + 1);
渲染时需要在列表顶部和底部添加空白占位元素以维持正确滚动高度:

<div style={{ height: `${startIndex * itemHeight}px` }} />
{visibleItems.map(item => (
<ListItem key={item.id} height={itemHeight} />
))}
<div style={{ height: `${(totalItems - endIndex - 1) * itemHeight}px` }} />
性能优化技巧
添加缓冲区(overscan)提前加载可视区域外的少量项目,避免快速滚动时出现空白:
const overscanCount = 5;
startIndex = Math.max(0, startIndex - overscanCount);
endIndex = Math.min(totalItems - 1, endIndex + overscanCount);
使用React.memo优化列表项组件,避免不必要的重新渲染:
const MemoizedListItem = React.memo(ListItem);
使用现有库简化实现
推荐使用成熟的虚拟列表库:

- react-window:轻量级基础方案
- react-virtualized:功能更全面
- @tanstack/react-virtual:现代化实现
react-window基础示例:
import { FixedSizeList as List } from 'react-window';
<List
height={600}
itemCount={10000}
itemSize={35}
width={300}
>
{({ index, style }) => (
<div style={style}>Row {index}</div>
)}
</List>
处理动态高度项目
当项目高度不固定时,需要额外处理:
- 预先测量并缓存项目高度
- 使用react-window的VariableSizeList
- 估算高度并在滚动时动态调整
react-window动态高度示例:
import { VariableSizeList as List } from 'react-window';
const rowHeights = new Array(1000).fill(true).map(() => 25 + Math.round(Math.random() * 50));
const getItemSize = index => rowHeights[index];
<List
height={600}
itemCount={1000}
itemSize={getItemSize}
width={300}
>
{({ index, style }) => (
<div style={style}>Row {index}</div>
)}
</List>






