Antd Virtual table fixed header

813 Views Asked by At

Based on this documentation https://4x.ant.design/components/table/#components-table-demo-virtual-list I've created VirtualTable component.

import React, { useState, useRef, useEffect } from 'react'
import { Table } from 'antd'
import classNames from 'classnames'
import ResizeObserver from 'rc-resize-observer'
import { VariableSizeGrid as Grid } from 'react-window'

const VirtualTable = (props) => {
  const { columns, scroll } = props
  const [tableWidth, setTableWidth] = useState(0)
  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) => {
        if (gridRef.current) {
          gridRef.current.scrollTo({
            scrollLeft,
          })
        }
      },
    })
    return obj
  })

  const resetVirtualGrid = () => {
    gridRef?.current?.resetAfterIndices({
      columnIndex: 0,
      shouldForceUpdate: true,
    })
  }

  useEffect(() => resetVirtualGrid, [tableWidth])

  const renderVirtualList = (rawData, { scrollbarSize, ref, onScroll }) => {
    ref.current = connectObject
    const totalHeight = rawData.length * 54
    return (
      <Grid
        ref={gridRef}
        className="virtual-grid"
        columnCount={mergedColumns.length}
        columnWidth={(index) => {
          const { width } = mergedColumns[index]
          return totalHeight > scroll.y && index === mergedColumns.length - 1 ? width - scrollbarSize - 1 : width
        }}
        height={scroll.y}
        rowCount={rawData.length}
        rowHeight={() => 54}
        width={tableWidth}
        onScroll={({ scrollLeft }) => {
          onScroll({
            scrollLeft,
          })
        }}
      >
        {({ columnIndex, rowIndex, style }) => (
          <div
            className={classNames('virtual-table-cell', {
              'virtual-table-cell-last': columnIndex === mergedColumns.length - 1,
            })}
            style={style}
          >
            {mergedColumns[columnIndex].dataIndex !== '' && !mergedColumns[columnIndex].render ? (
              <div> {rawData[rowIndex][mergedColumns[columnIndex].dataIndex]} </div>
            ) : (
              <div>
                {mergedColumns[columnIndex].render(
                  rawData[rowIndex][mergedColumns[columnIndex].dataIndex],
                  rawData[rowIndex]
                )}
              </div>
            )}
          </div>
        )}
      </Grid>
    )
  }

  return (
    <ResizeObserver
      onResize={({ width }) => {
        setTableWidth(width)
      }}
    >
      <Table
        {...props}
        className="virtual-table"
        columns={mergedColumns}
        pagination={false}
        components={{
          body: renderVirtualList,
        }}
      />
    </ResizeObserver>
  )
}

export default VirtualTable

However, when I tried to create a fixed header like this https://4x.ant.design/components/table/#components-table-demo-fixed-header I broke this table.

Any thoughts on how to implement a fixed header for Antd table based on the virtual table?

UPDATE:

I found that ant table based on https://table-react-component.vercel.app/demo/virtual-list but in my case renderVirtualList is not called

0

There are 0 best solutions below