react虚拟列表实现
虚拟列表实现原理
虚拟列表(Virtual List)通过仅渲染可视区域内的元素来优化长列表性能,避免一次性渲染所有数据导致的性能问题。核心思路是计算当前滚动位置对应的可见数据范围,动态渲染这部分元素并设置占位空间。
基本实现步骤
安装依赖库(如react-window或react-virtualized)或手动实现:
import { useState, useRef, useMemo } from 'react';
function VirtualList({ data, itemHeight, containerHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef(null);
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
const visibleData = useMemo(() =>
data.slice(startIndex, endIndex),
[data, startIndex, endIndex]
);
const totalHeight = data.length * itemHeight;
return (
<div
ref={containerRef}
style={{ height: containerHeight, overflow: 'auto' }}
onScroll={(e) => setScrollTop(e.target.scrollTop)}
>
<div style={{ height: totalHeight, position: 'relative' }}>
{visibleData.map((item, index) => (
<div
key={startIndex + index}
style={{
position: 'absolute',
top: (startIndex + index) * itemHeight,
height: itemHeight,
width: '100%'
}}
>
{item.content}
</div>
))}
</div>
</div>
);
}
使用现成库(react-window)
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
动态高度处理
对于不定高度的项目,可使用VariableSizeList:
import { VariableSizeList as List } from 'react-window';
const rowHeights = new Array(1000)
.fill(true)
.map(() => 25 + Math.round(Math.random() * 50));
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={index => rowHeights[index]}
width={300}
>
{Row}
</List>
);
性能优化建议
- 为列表项设置稳定的
key - 避免在列表项组件中使用内联函数
- 对复杂列表项使用
React.memo - 使用
useMemo缓存计算结果 - 考虑使用
shouldComponentUpdate优化渲染
常见问题解决
滚动跳动问题通常是由于动态高度计算不准确导致,可通过以下方式解决:
- 提前测量并缓存项目高度
- 使用
estimateSize属性提供预估高度 - 调用
resetAfterIndex方法重置位置计算
对于需要支持横向虚拟化的情况,react-window提供FixedSizeGrid组件处理二维虚拟列表。







