react-virtualized、react-window 和 react-virtual 都是为了解决 React 应用中渲染大量列表数据时的性能问题而设计的库。它们通过“虚拟化”技术,只渲染用户可见区域的 DOM 节点,从而大幅降低内存占用和渲染时间。react-virtualized 是早期的标准方案,功能全面但较重;react-window 是其继任者,更轻量且专注;react-virtual 则提供了基于 Hook 的无头(headless)方案,灵活性最高。
在 React 开发中,当需要渲染成千上万条数据时,直接渲染会导致页面卡顿甚至崩溃。这三个库都通过“虚拟化”技术解决了这个问题 —— 它们只渲染用户可见区域内的元素,其余部分用占位符代替。虽然目标一致,但它们的设计理念和适用场景却有明显差异。
这三个库最大的区别在于它们如何暴露虚拟化逻辑给开发者。
react-virtualized 提供了一整套封装好的组件。
<List>、<Grid> 或 <Table> 组件。// react-virtualized: 使用封装组件
import { List } from 'react-virtualized';
<List
width={600}
height={400}
rowCount={1000}
rowHeight={50}
rowRenderer={({ index, style }) => (
<div style={style}>Row {index}</div>
)}
/>
react-window 提供了更轻量的组件,但要求你通过渲染属性(Render Props)提供内容。
// react-window: 使用渲染属性
import { FixedSizeList } from 'react-window';
<FixedSizeList
height={400}
width={600}
itemCount={1000}
itemSize={50}
>
{({ index, style }) => (
<div style={style}>Row {index}</div>
)}
</FixedSizeList>
react-virtual 不提供 UI 组件,只提供一个 Hook。
useVirtual 获取虚拟化数据。// react-virtual: 使用 Hook
import { useVirtual } from 'react-virtual';
import { useRef } from 'react';
function VirtualList() {
const parentRef = useRef();
const virtualizer = useVirtual({
size: 1000,
parentRef,
estimateSize: () => 50,
});
return (
<div ref={parentRef} style={{ height: 400, overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.virtualItems.map(item => (
<div
key={item.key}
style={{
position: 'absolute',
top: 0,
transform: `translateY(${item.start}px)`,
height: item.size,
}}
>
Row {item.index}
</div>
))}
</div>
</div>
);
}
在处理非标准布局时,这三个库的表现截然不同。
react-virtualized 强制使用绝对定位。
// react-virtualized: 样式由库控制
// rowRenderer 接收的 style 包含 position: absolute
rowRenderer={({ index, style }) => (
<div style={style}> {/* 难以修改定位方式 */} </div>
)}
react-window 同样使用绝对定位,但结构更清晰。
outerRef 和 innerRef 访问容器。// react-window: 内容区域可控
<FixedSizeList
innerElementType="ul" // 可以将内部容器改为 ul
>
{({ index, style }) => (
<li style={style}>Item {index}</li>
)}
</FixedSizeList>
react-virtual 让你手动应用样式。
start 和 size 数据,自己决定怎么写样式。// react-virtual: 手动应用样式
<div
style={{
position: 'absolute',
top: 0,
left: 0,
transform: `translate3d(0, ${item.start}px, 0)`,
}}
>
{item.index}
</div>
选择库时,维护状态是一个关键因素,它关系到未来的升级成本和安全性。
react-virtualized 已进入维护模式。
react-window。react-window 处于稳定维护期。
react-virtual 活跃开发中。
| 特性 | react-virtualized | react-window | react-virtual |
|---|---|---|---|
| API 类型 | 封装组件 (Class) | 轻量组件 (Render Props) | Hook (无头) |
| DOM 控制 | 低 (固定结构) | 中 (内容可控) | 高 (完全手动) |
| 布局方式 | 绝对定位 | 绝对定位 | 手动控制 (绝对/相对) |
| 维护状态 | 维护模式 (Legacy) | 稳定维护 | 活跃开发 |
| 学习曲线 | 中 (配置项多) | 低 (直观) | 高 (需理解原理) |
react-virtualized 就像一台重型机床 🏭—— 功能强大但笨重,适合旧项目维护。如果你的代码库已经大量使用它,迁移成本可能高于收益,可以暂时保留。但在新项目中,它不再是首选。
react-window 就像一把标准电钻 🔩—— 轻便、可靠、适合大多数任务。如果你只需要渲染标准的长列表或网格,不需要复杂的自定义布局,选它最稳妥。它的 API 设计合理,文档完善,能满足 90% 的需求。
react-virtual 就像一套精密的手工工具 🛠️—— 灵活、强大,但需要更多技巧。如果你需要实现非标准的滚动效果、动态高度计算或与现有布局系统深度集成,它的 Hook 设计能给你最大自由。适合对性能和控制力有极致要求的团队。
总结:对于大多数新项目,优先选择 react-window。如果需要极致灵活性或正在使用 TanStack 生态,选择 react-virtual。尽量避免在新项目中引入 react-virtualized。
如果你需要极高的灵活性,希望完全控制 DOM 结构,或者正在使用 TanStack 生态系统,react-virtual 是理想方案。它基于 Hook 设计,无头(headless)特性让你可以自由组合样式和布局,非常适合需要定制化滚动行为或复杂布局的场景。
如果你的项目是旧代码库维护,且已经深度依赖 react-virtualized 的复杂组件(如 Table 或 Grid),继续使用它可以避免大规模重构。但在新项目中不建议选用,因为它主要基于 Class 组件,API 较重,且官方已建议转向更轻量的方案。
如果你需要快速实现标准的长列表或网格,且希望拥有稳定的维护和较小的包体积,react-window 是最佳选择。它由 react-virtualized 的同一作者开发,专为现代 React 优化,API 简洁,适合大多数通用的虚拟化场景。
Table of Contents generated with DocToc

Hooks for virtualizing scrollable elements in React
Enjoy this library? Try the entire TanStack! React Query, React Table, React Charts, React Form