import type { TableProps } from 'antd'; import { Table, theme } from 'antd'; import classNames from 'classnames'; import ResizeObserver from 'rc-resize-observer'; import React, { useEffect, useRef, useState } from 'react'; import { VariableSizeGrid as Grid } from 'react-window'; const VirtualTable = (props: TableProps) => { const { columns, scroll } = props; const [tableWidth, setTableWidth] = useState(0); const { token } = theme.useToken(); const widthColumnCount = columns!.filter(({ width }) => !width).length; const mergedColumns = columns!.map((column) => { if (column.width) { return column; } return { ...column, width: Math.floor(tableWidth / widthColumnCount), }; }); const gridRef = useRef(); const [connectObject] = useState(() => { const obj = {}; Object.defineProperty(obj, 'scrollLeft', { get: () => { if (gridRef.current) { return gridRef.current?.state?.scrollLeft; } return null; }, set: (scrollLeft: number) => { if (gridRef.current) { gridRef.current.scrollTo({ scrollLeft }); } }, }); return obj; }); const resetVirtualGrid = () => { gridRef.current?.resetAfterIndices({ columnIndex: 0, shouldForceUpdate: true, }); }; useEffect(() => resetVirtualGrid, [tableWidth]); const renderVirtualList = (rawData: readonly object[], { scrollbarSize, ref, onScroll }: any) => { ref.current = connectObject; const totalHeight = rawData.length * 54; return ( { const { width } = mergedColumns[index]; return totalHeight > (scroll?.y as number) && index === mergedColumns.length - 1 ? (width as number) - scrollbarSize - 1 : (width as number); }} height={scroll!.y as number} rowCount={rawData.length} rowHeight={() => 54} width={tableWidth} onScroll={({ scrollLeft }: { scrollLeft: number }) => { onScroll({ scrollLeft }); }} > {({ columnIndex, rowIndex, style, }: { columnIndex: number; rowIndex: number; style: React.CSSProperties; }) => (
{(rawData[rowIndex] as any)[(mergedColumns as any)[columnIndex].dataIndex]}
)}
); }; return ( { setTableWidth(width); }} > ); }; // Usage const columns = [ { title: 'A', dataIndex: 'key', width: 150 }, { title: 'B', dataIndex: 'key' }, { title: 'C', dataIndex: 'key' }, { title: 'D', dataIndex: 'key' }, { title: 'E', dataIndex: 'key', width: 200 }, { title: 'F', dataIndex: 'key', width: 100 }, ]; const data = Array.from({ length: 100000 }, (_, key) => ({ key })); const App: React.FC = () => ( ); export default App;