跳到主要内容

场景组件

场景组件总览

react-virtuoso 内置了几个"专场景组件",一个库覆盖绝大多数虚拟化需求:

组件场景
Virtuoso通用列表(动态高度 / 无限加载 / 聊天)
VirtuosoGrid网格 / 瀑布流(多列、不定宽)
TableVirtuoso表格(海量行 + 吸顶表头)
GroupedVirtuoso分组列表(吸顶组头)

场景 1:VirtuosoGrid(瀑布流 / 网格)

import { VirtuosoGrid } from 'react-virtuoso';

<VirtuosoGrid
style={{ height: '500px' }}
data={photos}
listClassName="grid" // 网格容器类名(用 className,不用 components)
itemClassName="grid-item" // 每一项类名
itemContent={(index, photo) => <img src={photo.url} loading="lazy" />}
/>
.grid { display: flex; flex-wrap: wrap; }
.grid-item { width: 33.33%; box-sizing: border-box; padding: 4px; }
.grid-item img { width: 100%; display: block; }

要点:网格布局靠 CSSflex-wrap / grid),virtuoso 只负责"只渲染视口附近的行"。

场景 2:TableVirtuoso(海量表格 + 吸顶表头)

import { TableVirtuoso } from 'react-virtuoso';

<TableVirtuoso
style={{ height: '400px' }}
data={orders}
fixedHeaderContent={() => ( // 吸顶表头
<tr>
<th>订单号</th>
<th>金额</th>
<th>状态</th>
</tr>
)}
itemContent={(index, order) => (
<>
<td>{order.no}</td>
<td>{order.amount}</td>
<td>{order.status}</td>
</>
)}
/>
  • 自动产出 <table>,表头 fixedHeaderContent 吸顶;
  • 10 万行 × 20 列这种规模也能保持流畅(computeItemKeyorder.id)。

场景 3:GroupedVirtuoso(分组 + 吸顶组头)

import { GroupedVirtuoso } from 'react-virtuoso';

const groupCounts = [3, 5, 2]; // 每组各有多少条
const data = [...]; // 拍平的完整数据

<GroupedVirtuoso
style={{ height: '400px' }}
groupCounts={groupCounts}
groupContent={(index, group) => (
<div className="group-header">分组 {index + 1}(吸顶)</div>
)}
itemContent={(index, groupIndex, item) => (
<div>{item.name}</div>
)}
/>

适合通讯录按首字母分组、订单按状态分组这类场景,组头滚动时吸顶。

场景 4:聊天消息流(反向 + 跟随最新)

聊天的特殊性:从底部开始、新消息自动滚到底、往上翻加载历史

import { useState } from 'react';
import { Virtuoso } from 'react-virtuoso';

function Chat() {
const [messages, setMessages] = useState(initialMessages);
const [atBottom, setAtBottom] = useState(true);

const sendMessage = (text) => {
setMessages((prev) => [...prev, { id: Date.now(), text }]);
};

return (
<Virtuoso
style={{ height: '400px' }}
data={messages}
followOutput={atBottom ? 'smooth' : false} // 在底部才平滑跟随新消息
atBottomStateChange={(isAtBottom) => setAtBottom(isAtBottom)} // 记录是否在底部
itemContent={(index, msg) => <MessageBubble msg={msg} />}
/>
);
}

要点:

  • followOutput:用户在底部时新消息自动平滑滚到底;用户往上翻历史时不打扰
  • atBottomStateChange:同步"是否在底部",配合 followOutput 判断要不要跟随;
  • 往上加载历史:用 firstItemIndex(给已加载的最早一条一个初始 index)+ startReached 在顶部加载更早的消息;
  • 每条消息高度不同(长文本 / 图片),自动测量天然适配。

场景清单

需求用哪个关键 prop
通用长列表Virtuosodata / itemContent
无限加载 feedVirtuosoendReached
瀑布流 / 多列VirtuosoGridlistClassName + CSS
海量表格 + 吸顶表头TableVirtuosofixedHeaderContent
分组列表 + 吸顶组头GroupedVirtuosogroupCounts / groupContent
聊天消息流VirtuosofollowOutput / firstItemIndex