如何在TanStack react-table v8中集成react-virtual(v3 beta版)
TanStack React-Table v8 集成 React-Virtual v3.x 实现行虚拟化
针对你的需求,我调整了代码实现两个库的集成,完整代码如下:
import type { ReactElement } from "react"; import { useRef, useEffect } from "react"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, } from "./style"; import { flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table"; import type { ColumnDef } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; interface TableProps { columns: Array<ColumnDef<any, string>>; data: any; rowHeight?: number; // 可选,自定义行高 } function CustomTable(props: TableProps): ReactElement { const { columns, data, rowHeight = 48 } = props; const tableContainerRef = useRef<HTMLDivElement>(null); const tableBodyRef = useRef<HTMLTableSectionElement>(null); const tableInstance = useReactTable({ columns, data, getCoreRowModel: getCoreRowModel(), }); const rowVirtualizer = useVirtualizer({ count: tableInstance.getRowModel().rows.length, getScrollElement: () => tableContainerRef.current, estimateSize: () => rowHeight, // 当虚拟列表更新时同步表格体高度 onChange: () => { if (tableBodyRef.current) { tableBodyRef.current.style.height = `${rowVirtualizer.getTotalSize()}px`; } }, }); // 表格数据变化时更新虚拟列表计数 useEffect(() => { rowVirtualizer.setCount(tableInstance.getRowModel().rows.length); }, [tableInstance.getRowModel().rows.length, rowVirtualizer]); return ( <div ref={tableContainerRef} style={{ height: "500px", // 可根据需求调整容器高度 overflow: "auto", }} > <Table style={{ width: "100%", borderCollapse: "collapse" }}> <TableHead> {tableInstance.getHeaderGroups().map(headerGroup => { return ( <TableRow key={headerGroup.id}> {headerGroup.headers.map(header => { return ( <TableHeaderCell key={header.id}> <span> {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} </span> </TableHeaderCell> ); })} </TableRow> ); })} </TableHead> <TableBody ref={tableBodyRef} style={{ position: "relative" }}> {/* 占位元素:撑开表格体高度,保证滚动范围正确 */} <div style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: "absolute", top: 0, left: 0, right: 0, pointerEvents: "none", }} /> {/* 仅渲染视口内可见的行 */} {rowVirtualizer.getVirtualItems().map(virtualItem => { const row = tableInstance.getRowModel().rows[virtualItem.index]; return ( <TableRow $border key={row.id} style={{ position: "absolute", top: 0, left: 0, right: 0, transform: `translateY(${virtualItem.start}px)`, }} > {row.getVisibleCells().map(cell => { return ( <TableCell key={cell.id}> <span> {flexRender( cell.column.columnDef.cell, cell.getContext() )} </span> </TableCell> ); })} </TableRow> ); })} </TableBody> </Table> </div> ); } export default CustomTable;
关键改动说明
- 滚动容器调整:把滚动容器改为外层
div,设置固定高度和滚动属性,确保react-virtual能正确捕获滚动事件。 - 虚拟行渲染逻辑:不再全量渲染所有行,而是通过
rowVirtualizer.getVirtualItems()获取视口内可见的行,用绝对定位和transform将行放到正确位置。 - 滚动范围保证:添加占位元素,用虚拟列表的总高度撑开表格体,确保容器滚动条的范围正确。
- 数据同步处理:监听表格行数量变化,同步更新虚拟列表的计数,避免数据更新后虚拟列表不生效。
- 行高灵活配置:新增
rowHeight参数,默认48px,替换原有的15px估算值,提升虚拟列表的定位准确性。
内容的提问来源于stack exchange,提问作者Oren Papa
相关产品推荐
相关产品推荐

