react-virtualized vs react-infinite vs react-list vs react-tiny-virtual-list vs react-window
React 列表虚拟化方案深度对比与选型指南
react-virtualizedreact-infinitereact-listreact-tiny-virtual-listreact-window类似的npm包:

React 列表虚拟化方案深度对比与选型指南

这些库旨在解决 React 应用中渲染大量数据时的性能瓶颈。react-virtualized 和 react-window 采用窗口化(windowing)技术,仅渲染可视区域内的 DOM 节点,大幅提升性能。react-infinite 侧重于无限加载逻辑,但通常不具备虚拟化能力。react-list 和 react-tiny-virtual-list 提供了介于两者之间的解决方案,分别在灵活性和体积上有所侧重。开发者需根据项目对性能、维护性及功能复杂度的需求进行选择。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
react-virtualized2,005,69727,0732.24 MB02 年前MIT
react-infinite02,682243 kB101-BSD-3-Clause
react-list01,96835.3 kB733 个月前MIT
react-tiny-virtual-list02,482-558 年前MIT
react-window017,208243 kB04 天前MIT

React 列表虚拟化方案深度对比:从 react-infinite 到 react-window

在构建数据密集型 React 应用时,列表渲染性能往往是首要瓶颈。当数据量达到成千上万条时,直接渲染所有 DOM 节点会导致页面卡顿甚至崩溃。本文对比的五款库 —— react-infinite、react-list、react-tiny-virtual-list、react-virtualized 和 react-window —— 提供了不同的解决思路。我们将深入探讨它们的核心机制、API 设计及维护状态,帮助你做出架构决策。

🏗️ 核心机制:无限加载 vs 窗口虚拟化

性能优化的核心在于减少 DOM 节点数量。

react-infinite 侧重于逻辑上的无限加载,而非 DOM 优化。

  • 它监听滚动事件触发数据加载回调。
  • 默认情况下,它倾向于保留已加载的 DOM 节点,数据量增大时性能会线性下降。
// react-infinite: 监听加载事件
<Infinite
  elementHeight={200}
  containerHeight={600}
  onInfiniteLoad={this.handleLoadMore}
>
  {items.map(item => <div key={item.id}>{item.name}</div>)}
</Infinite>

react-virtualized 和 react-window 采用真正的窗口化(Windowing)技术。

  • 它们只渲染可视区域及其缓冲区的节点。
  • 无论数据总量多少,DOM 节点数量保持恒定,性能稳定。
// react-virtualized: 使用 List 组件
<List
  width={300}
  height={600}
  rowCount={items.length}
  rowHeight={50}
  rowRenderer={({ index, style }) => (
    <div key={items[index].id} style={style}>{items[index].name}</div>
  )}
/>
// react-window: 使用 FixedSizeList 组件
<FixedSizeList
  height={600}
  itemCount={items.length}
  itemSize={50}
  width={300}
>
  {({ index, style }) => (
    <div key={items[index].id} style={style}>{items[index].name}</div>
  )}
</FixedSizeList>

react-list 和 react-tiny-virtual-list 也提供虚拟化。

  • react-list 允许更灵活的 item 渲染器配置。
  • react-tiny-virtual-list 专注于极简实现。
// react-list: 使用 itemRenderer
<List
  itemRenderer={this.renderItem}
  length={items.length}
  estimateItemSize={50}
/>
// react-tiny-virtual-list: 简洁 API
<VirtualList
  width={300}
  height={600}
  itemSize={50}
  items={items}
  renderItem={({ index, style }) => (
    <div key={items[index].id} style={style}>{items[index].name}</div>
  )}
/>

🛠️ API 设计:类组件 vs 现代 Hooks

API 的设计风格直接影响开发体验和代码可维护性。

react-virtualized 诞生于 React 类组件时代。

  • 大量依赖 ref 回调和类组件生命周期。
  • 与现代 Hooks 代码混合使用时略显繁琐。
// react-virtualized: 通常需要配合 ref 使用
class MyList extends React.Component {
  render() {
    return <List ref={this.listRef} ... />;
  }
}

react-window 为现代 React 而生。

  • 完美支持函数组件和 Hooks。
  • API 更直观,减少了样板代码。
// react-window: 原生支持函数组件
function MyList({ items }) {
  return (
    <FixedSizeList itemCount={items.length} ...>
      {({ index, style }) => <div style={style}>{items[index]}</div>}
    </FixedSizeList>
  );
}

react-infinite 同样基于较旧的 React 模式。

  • 配置项较为分散,往往需要手动管理容器高度。
// react-infinite: 配置较为繁琐
<Infinite
  useWindowScroll={true}
  containerHeight={this.state.height}
  ...
/>

react-list 和 react-tiny-virtual-list 介于两者之间。

  • react-list 提供稳定的 API,但配置项较多。
  • react-tiny-virtual-list 力求简单,但扩展性有限。
// react-tiny-virtual-list: 配置直观
<VirtualList
  items={items}
  renderItem={...}
/>

⚠️ 维护状态与弃用警告

这是选型中最关键的非技术因素。

react-virtualized 已不再积极维护。

  • 官方 README 明确建议新用户迁移至 react-window。
  • 虽然它功能强大(支持复杂的网格、表格、自动调整大小),但修复 bug 和新特性更新已停止。
  • 建议: 仅在维护旧代码库时使用,新项目请勿选用。

react-infinite 基本处于停滞状态。

  • 最后更新时间久远,不再适应现代 React 生态。
  • 缺乏虚拟化核心能力,不适合大数据量场景。
  • 建议: 避免使用,改用具备虚拟化能力的库。

react-window 是当前标准。

  • 由 react-virtualized 同一作者维护,活跃度高。
  • 社区支持好,文档完善。
  • 建议: 新项目默认首选。

react-list 和 react-tiny-virtual-list 状态稳定。

  • 适合特定需求,但社区活跃度不如 react-window。
  • 建议: 作为备选方案评估。

📐 功能覆盖:网格、可变高度与自动调整

不同场景需要不同的功能支持。

可变高度列表:

  • react-virtualized 使用 CellMeasurer 配合 List,配置复杂但功能强。
  • react-window 提供 VariableSizeList,API 更简洁,需手动通知尺寸变化。
  • react-list 通过 estimateItemSize 和重新渲染处理。
  • react-tiny-virtual-list 支持有限,通常需固定高度或简单估算。
  • react-infinite 不支持真正的可变高度虚拟化。
// react-window: 可变高度
<VariableSizeList
  itemSize={index => heights[index]}
  itemCount={items.length}
  ...
/>
// 需调用 listRef.resetAfterIndex(index) 通知更新
// react-virtualized: 可变高度
<CellMeasurerCache defaultHeight={100}>
  <List
    rowHeight={cache.rowHeight}
    rowRenderer={({ index, style, parent }) => (
      <CellMeasurer cache={cache} index={index} parent={parent}>
        {({ measure, didMeasure }) => (
          <div style={style} onLoad={measure}>...</div>
        )}
      </CellMeasurer>
    )}
  />
</CellMeasurerCache>

网格布局(Grid):

  • react-virtualized 和 react-window 均提供 Grid 组件。
  • react-list、react-tiny-virtual-list、react-infinite 主要专注于单维列表。
// react-window: 网格
<FixedSizeGrid
  columnCount={12}
  rowCount={100}
  columnWidth={100}
  rowHeight={50}
  ...
/>

📊 总结对比表

特性react-windowreact-virtualizedreact-listreact-tiny-virtual-listreact-infinite
虚拟化核心✅ 是✅ 是✅ 是✅ 是❌ 否 (通常)
维护状态🟢 活跃🔴 不再积极维护🟡 稳定🟡 稳定🔴 停滞
API 风格🪝 Hooks 友好🏛️ 类组件为主🛠️ 配置型🧸 极简🕰️ 旧式
可变高度✅ 支持✅ 支持 (复杂)✅ 支持⚠️ 有限❌ 不支持
网格支持✅ 支持✅ 支持❌ 否❌ 否❌ 否
推荐场景新项目首选旧项目维护特殊定制轻量场景不推荐

💡 架构师建议

在选择列表库时,请遵循以下原则:

  1. 默认选择 react-window:它是 react-virtualized 的精神继承者,更轻、更快、更符合现代 React 开发习惯。除非你有非常特殊的理由,否则不要偏离这个默认选项。

  2. 避免 react-virtualized 新接入:尽管它功能丰富,但维护状态已改变。引入它意味着未来可能需要重构迁移至 react-window,这会带来不必要的技术债务。

  3. 警惕 react-infinite 的性能陷阱:很多开发者误以为“无限加载”等于“性能优化”。实际上,如果没有虚拟化技术,加载 10,000 条数据依然会卡死浏览器。确保你选择的是具备“窗口化”能力的库。

  4. 评估复杂性:如果你的列表需要复杂的网格布局或交叉轴滚动,react-window 和 react-virtualized 是唯二的支持者。对于简单列表,react-tiny-virtual-list 可以作为轻量替代,但需权衡未来扩展性。

最终结论:现代 React 架构中,react-window 是列表虚拟化的事实标准。它平衡了性能、体积和开发体验,是大多数工程场景下的最优解。

如何选择: react-virtualized vs react-infinite vs react-list vs react-tiny-virtual-list vs react-window

  • react-virtualized:

    仅用于维护旧项目。该库已不再积极维护,官方明确建议新用户迁移至 react-window。虽然功能全面(支持网格、表格等),但包体积较大且 API 基于较旧的 React 模式,新项目应避免使用。

  • react-infinite:

    不推荐用于高性能场景。该库主要处理无限加载逻辑,往往渲染所有 DOM 节点,导致长列表性能急剧下降。仅适用于数据量极小且只需简单分页加载的遗留系统,现代应用应避开。

  • react-list:

    适用于需要高度自定义渲染逻辑的场景。如果你需要比 react-window 更细粒度的控制,且能接受稍复杂的配置,它是一个稳定的备选方案。但在大多数标准列表场景中,react-window 通常更易上手。

  • react-tiny-virtual-list:

    适用于对包体积极度敏感的小型项目。如果你只需要基础的虚拟列表功能,且希望依赖尽可能少,这是一个轻量级选择。但功能丰富度不如 react-window,复杂场景可能受限。

  • react-window:

    首选方案。如果你正在启动新项目,react-window 是最佳选择。它由 react-virtualized 的作者维护,专为现代 React 设计,支持 Hooks,体积更小且 API 更简洁。除非你有特殊的遗留需求,否则应优先考虑它。

react-virtualized的README

React virtualized

React components for efficiently rendering large lists and tabular data. Check out the demo for some examples.

If you like this project, 🎉 become a sponsor or ☕ buy me a coffee

Sponsors

The following wonderful companies have sponsored react-virtualized:

Learn more about becoming a sponsor!

A word about react-window

If you're considering adding react-virtualized to a project, take a look at react-window as a possible lighter-weight alternative. Learn more about how the two libraries compare here.

Getting started

Install react-virtualized using npm.

npm install react-virtualized --save

ES6, CommonJS, and UMD builds are available with each distribution. For example:

// Most of react-virtualized's styles are functional (eg position, size).
// Functional styles are applied directly to DOM elements.
// The Table component ships with a few presentational styles as well.
// They are optional, but if you want them you will need to also import the CSS file.
// This only needs to be done once; probably during your application's bootstrapping process.
import 'react-virtualized/styles.css';

// You can import any component you want as a named export from 'react-virtualized', eg
import {Column, Table} from 'react-virtualized';

// But if you only use a few react-virtualized components,
// And you're concerned about increasing your application's bundle size,
// You can directly import only the components you need, like so:
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import List from 'react-virtualized/dist/commonjs/List';

Note webpack 4 makes this optimization itself, see the documentation.

If the above syntax looks too cumbersome, or you import react-virtualized components from a lot of places, you can also configure a Webpack alias. For example:

// Partial webpack.config.js
{
  alias: {
    'react-virtualized/List': 'react-virtualized/dist/es/List',
  },
  ...rest
}

Then you can just import like so:

import List from 'react-virtualized/List';

// Now you can use <List {...props} />

You can also use a global-friendly UMD build:

<link rel="stylesheet" href="path-to-react-virtualized/styles.css" />
<script src="path-to-react-virtualized/dist/umd/react-virtualized.js"></script>

Now you're ready to start using the components. You can learn more about which components react-virtualized has to offer below.

Dependencies

React Virtualized has very few dependencies and most are managed by NPM automatically. However the following peer dependencies must be specified by your project in order to avoid version conflicts: react, react-dom. NPM will not automatically install these for you but it will show you a warning message with instructions on how to install them.

Pure Components

By default all react-virtualized components use shallowCompare to avoid re-rendering unless props or state has changed. This occasionally confuses users when a collection's data changes (eg ['a','b','c'] => ['d','e','f']) but props do not (eg array.length).

The solution to this is to let react-virtualized know that something external has changed. This can be done a couple of different ways.

Pass-thru props

The shallowCompare method will detect changes to any props, even if they aren't declared as propTypes. This means you can also pass through additional properties that affect cell rendering to ensure changes are detected. For example, if you're using List to render a list of items that may be re-sorted after initial render- react-virtualized would not normally detect the sort operation because none of the properties it deals with change. However you can pass through the additional sort property to trigger a re-render. For example:

<List {...listProps} sortBy={sortBy} />
Public methods

Grid and Collection components can be forcefully re-rendered using forceUpdate. For Table and List, you'll need to call forceUpdateGrid to ensure that the inner Grid is also updated. For MultiGrid, you'll need to call forceUpdateGrids to ensure that the inner Grids are updated.

Documentation

API documentation available here.

There are also a couple of how-to guides:

Examples

Examples for each component can be seen in the documentation.

Here are some online demos of each component:

And here are some "recipe" type demos:

Supported Browsers

react-virtualized aims to support all evergreen browsers and recent mobile browsers for iOS and Android. IE 9+ is also supported (although IE 9 will require some user-defined, custom CSS since flexbox layout is not supported).

If you find a browser-specific problem, please report it along with a repro case. The easiest way to do this is probably by forking this Plunker.

Friends

Here are some great components built on top of react-virtualized:

  • react-infinite-calendar: Infinite scrolling date-picker with localization, themes, keyboard support, and more
  • react-sortable-hoc: Higher-order components to turn any list into an animated, touch-friendly, sortable list
  • react-sortable-tree: Drag-and-drop sortable representation of hierarchical data
  • react-virtualized-checkbox: Checkbox group component with virtualization for large number of options
  • react-virtualized-select: Drop-down menu for React with windowing to support large numbers of options.
  • react-virtualized-tree: A reactive tree component that aims to render large sets of tree structured data in an elegant and performant way
  • react-timeline-9000: A calendar timeline component that is capable of displaying and interacting with a large number of items

Contributions

Use GitHub issues for requests.

I actively welcome pull requests; learn how to contribute.

Changelog

Changes are tracked in the changelog.

License

react-virtualized is available under the MIT License.