You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于react-virtualized实现多表格:添加跨页宽的头尾区域

Hey there! Let's figure out how to build those repeating header-table-footer sections with react-virtualized for smooth performance, even with lots of groups. Here's a solid approach tailored to your needs:

Core Idea

We'll use react-virtualized's List component to virtualize the entire collection of header-table-footer groups. Each "row" in the List will be a full group (header + virtualized table + footer). This way, only the groups visible in the viewport get rendered, which keeps things fast even with hundreds of groups.

Step-by-Step Implementation

First, make sure you have react-virtualized installed:

npm install react-virtualized

Then, here's the complete code example:

import React from 'react';
import { List, Table, Column, AutoSizer } from 'react-virtualized';
import 'react-virtualized/styles.css'; // Don't forget the default styles!

// Component for a single header-table-footer group
const TableGroup = ({ groupData }) => {
  // Define fixed heights for consistency (adjust these to your needs)
  const HEADER_HEIGHT = 50;
  const FOOTER_HEIGHT = 50;
  const ROW_HEIGHT = 40;
  const TABLE_HEIGHT = groupData.tableRows.length * ROW_HEIGHT;

  // Helper to fetch table rows
  const rowGetter = ({ index }) => groupData.tableRows[index];

  return (
    <div style={{ width: '100%', marginBottom: '12px' }}>
      {/* Full-width Header */}
      <div style={{
        width: '100%',
        height: HEADER_HEIGHT,
        backgroundColor: '#f8f9fa',
        display: 'flex',
        alignItems: 'center',
        padding: '0 16px',
        fontWeight: 600,
        borderBottom: '1px solid #e9ecef'
      }}>
        {groupData.headerText}
      </div>

      {/* Virtualized Table */}
      <AutoSizer>
        {({ width }) => (
          <Table
            width={width}
            height={TABLE_HEIGHT}
            headerHeight={ROW_HEIGHT}
            rowHeight={ROW_HEIGHT}
            rowCount={groupData.tableRows.length}
            rowGetter={rowGetter}
            bordered={false}
          >
            <Column label="ID" dataKey="id" width={100} />
            <Column label="Name" dataKey="name" width={220} />
            <Column label="Details" dataKey="details" width={180} />
            {/* Add more columns as needed */}
          </Table>
        )}
      </AutoSizer>

      {/* Full-width Footer */}
      <div style={{
        width: '100%',
        height: FOOTER_HEIGHT,
        backgroundColor: '#f8f9fa',
        display: 'flex',
        alignItems: 'center',
        padding: '0 16px',
        color: '#6c757d',
        borderTop: '1px solid #e9ecef'
      }}>
        {groupData.footerText}
      </div>
    </div>
  );
};

// Parent component to render all virtualized groups
const VirtualizedGroupedTables = () => {
  // Sample data - replace with your actual data
  const groups = [
    {
      headerText: 'Customer Records',
      footerText: 'Total: 12 customers',
      tableRows: Array.from({ length: 12 }, (_, i) => ({
        id: i + 1,
        name: `Customer ${i + 1}`,
        details: `Tier ${i % 3 + 1}`
      }))
    },
    {
      headerText: 'Product Inventory',
      footerText: 'Total: 18 products',
      tableRows: Array.from({ length: 18 }, (_, i) => ({
        id: i + 1,
        name: `Product ${i + 1}`,
        details: `In Stock: ${Math.floor(Math.random() * 100)}`
      }))
    },
    {
      headerText: 'Order History',
      footerText: 'Total: 25 orders',
      tableRows: Array.from({ length: 25 }, (_, i) => ({
        id: i + 1,
        name: `Order #${i + 1000}`,
        details: `${Math.floor(Math.random() * 500)}$`
      }))
    },
    // Add as many groups as you need!
  ];

  // Calculate height for each group in the List
  const getGroupHeight = ({ index }) => {
    const group = groups[index];
    return 50 + (group.tableRows.length * 40) + 50; // Header + Table Rows + Footer
  };

  // Render each group in the virtualized List
  const renderGroup = ({ index, key, style }) => (
    <div key={key} style={style}>
      <TableGroup groupData={groups[index]} />
    </div>
  );

  return (
    <div style={{ height: '90vh', width: '100%', padding: '16px' }}>
      <AutoSizer>
        {({ width, height }) => (
          <List
            width={width}
            height={height}
            rowCount={groups.length}
            rowHeight={getGroupHeight}
            rowRenderer={renderGroup}
          />
        )}
      </AutoSizer>
    </div>
  );
};

export default VirtualizedGroupedTables;

Key Details to Note

  • Virtualization Layers: We have two levels of virtualization here:
    1. The outer List virtualizes the entire header-table-footer groups.
    2. Each inner Table virtualizes its own rows, which is crucial if your tables have lots of data.
  • Fixed Heights: Using fixed heights for headers, footers, and table rows makes it easy for react-virtualized to calculate scroll positions accurately. If you need variable row heights, you can use CellMeasurer from react-virtualized to dynamically compute them.
  • Responsiveness: AutoSizer ensures the components fit the available space in their parent container, making the layout responsive.
  • Styling: The inline styles are just examples—you can replace them with CSS classes or a styling solution of your choice (like styled-components) to match your app's design.

Adjustments for Your Use Case

  • If you want tables with internal scrolling (instead of expanding to fit all rows), set a fixed height for the Table (e.g., height: 300) instead of calculating it from row count. The group height would then be 50 + 300 + 50.
  • For dynamic content that changes height, you'll need to update the List's cache or force a re-measure using react-virtualized's API.

内容的提问来源于stack exchange,提问作者Danny Larsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:53:09