Search code examples
javascriptreactjsdatagridcell

React BaseTable rowSpan "flickering"


Problem

As seen in the interactive BaseTable API playground here, the spanning rows flicker on/off when I start scrolling.

This is a known bug in the library, and there have been numerous issues posted regarding it: https://github.com/Autodesk/react-base-table/issues/156

However, there does not seem to be any fix available. A comment on there states that this could be done, but I am not sure where in the code this would be placed:

      const overscanBackward =
        !isScrolling || verticalScrollDirection === 'backward'
          ? Math.max(1, overscanCountResolved)
          : 1;

What the table looks like

enter image description here

Code

Same code as in the playground:

    const data = [
    {
      key: 1,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 2,
      "column-0": "Row 1 - Col 0",
      "column-1": "Row 1 - Col 1",
      "column-2": "Row 1 - Col 1",
      "column-3": "Row 1 - Col 1",
      "column-4": "Row 1 - Col 1"
    },
    {
      key: 3,
      "column-0": "Row 2 - Col 0",
      "column-1": "Row 2 - Col 1",
      "column-2": "Row 2 - Col 1",
      "column-3": "Row 2 - Col 1",
      "column-4": "Row 2 - Col 1"
    },
    {
      key: 4,
      "column-0": "Row 3 - Col 0",
      "column-1": "Row 3 - Col 1",
      "column-2": "Row 3 - Col 1",
      "column-3": "Row 3 - Col 1",
      "column-4": "Row 3 - Col 1"
    },
    {
      key: 5,
      "column-0": "Row 4 - Col 0",
      "column-1": "Row 4 - Col 1",
      "column-2": "Row 4 - Col 1",
      "column-3": "Row 4 - Col 1",
      "column-4": "Row 4 - Col 1"
    },
    {
      key: 6,
      "column-0": "Row 5 - Col 0",
      "column-1": "Row 5 - Col 1",
      "column-2": "Row 5 - Col 1",
      "column-3": "Row 5 - Col 1",
      "column-4": "Row 5 - Col 1"
    },
    {
      key: 7,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 8,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 9,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 10,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 11,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 12,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 13,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 14,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 15,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    },
    {
      key: 16,
      "column-0": "Row 0 - Col 0",
      "column-1": "Row 0 - Col 1",
      "column-2": "Row 0 - Col 1",
      "column-3": "Row 0 - Col 1",
      "column-4": "Row 0 - Col 1"
    }
  ];

  const columns = [
    {
      dataKey: "column-0",
      key: "column-0",
      resizable: true,
      title: "Column 0",
      width: 150
    },
    {
      dataKey: "column-1",
      key: "column-1",
      resizable: true,
      title: "Column 1",
      width: 150
    },
    {
      dataKey: "column-2",
      key: "column-2",
      resizable: true,
      title: "Column 2",
      width: 150
    },
    {
      dataKey: "column-3",
      key: "column-3",
      resizable: true,
      title: "Column 3",
      width: 150
    },
    {
      dataKey: "column-4",
      key: "column-4",
      resizable: true,
      title: "Column 4",
      width: 150
    }
  ];

const rowSpanIndex = 0

const rowSpanArr = [5,2,3,2,5];
  columns[rowSpanIndex].rowSpan = ({ rowData, rowIndex }) => {
  console.log(rowIndex)
        
    let acc = 0
    for (let [index, x] of rowSpanArr.entries()){
      if (acc === rowIndex){
        acc = acc + x
        console.log("rowIndex:", rowIndex)
        console.log("rowSpanArr[index]:", rowSpanArr[index])
        return rowSpanArr[index]
      } 
      console.log(acc)
      acc = acc + x
    }
    
 };

const rowRenderer = ({ rowData, rowIndex, cells, columns }) => {
  const rowSpan = columns[rowSpanIndex].rowSpan({ rowData, rowIndex })
  if (rowSpan > 1) {
    const cell = cells[rowSpanIndex]
    const style = {
      ...cell.props.style,
      backgroundColor:"powderblue",
      height: rowSpan * 50 - 1,
      alignSelf: 'flex-start',
      zIndex: 1,
    }
    cells[rowSpanIndex] = React.cloneElement(cell, { style })
  }
  return cells
}

export default () => (
  <Table
    fixed
    columns={columns}
    data={data}
    rowRenderer={rowRenderer}
    overscanRowCount={2}
  />
)

Does anyone have any idea of what a temporary fix would look like? I really need this feature..


Solution

  • A solution has been found! The code underneath is for a little more complex example, but I think the procedure can be used.

    columns[rowSpanIndex].rowSpan = ({ rowIndex }) => {
        let acc = 0;
        for (let [index, x] of rowSpanArr.entries()) {
          if (acc === rowIndex) {
            acc = acc + x;
    
            return rowSpanArr[index];
          }
    
          acc = acc + x;
        }
      };
    
    const rowRenderer = ({ rowData, rowIndex, cells, columns }) => {
        // for the rows which should not span across any other rows
        const rowSpan = columns[rowSpanIndex].rowSpan({ rowData, rowIndex });
        if (rowSpan === undefined) {
          const cell = cells[rowSpanIndex];
          let style = {
            ...cell.props.style,
            backgroundColor: "white",
            color: "white",
            alignSelf: "flex-start",
            zIndex: 3
          };
    
          cells[rowSpanIndex] = React.cloneElement(cell, { style });
        }
        if (rowSpan > 1) {
        // for the spanning rows
          const cell = cells[rowSpanIndex];
          const style = {
            ...cell.props.style,
            backgroundColor: "white",
            height: rowSpan * 48 - 1,
            alignSelf: "flex-start",
            zIndex: 1
          };
          cells[rowSpanIndex] = React.cloneElement(cell, { style });
        }
    
    

    Along with the CSS

    .BaseTable__row-cell{
      align-items: flex-start;
      }