3

I am trying to make a nice Result View for looking at results from an SQL query. These results might contain thousands of results so React Virtualized was chosen to avoid rendering all the rows. The MultiGrid component was chosen so that the column names from the query are stickied to the top of the view. The component looks like this:

Multigrid component

The MultiGrid has Dynamic Width, using Cell Measurer. The code is heavily inspired from the example here. My problem is that the component renders really slowly, and in the cases where the component has been rendered, then hidden, and then rendered again, the entire app freezes for a minute or more. There is obviously something that is rendered that should not be, but I am unsure where the problem lies. I tried clearing the CellMeasurerCache but that did not seem to work. The code for the MultiGrid is as follows:

const useStyles = makeStyles((theme) => ({
  tableWrapper: {
    minHeight: 200,
    height: '100%',
    width: '100%',
    resize: 'vertical',
    overflowY: 'hidden',
    scrollbarWidth: 'none',
    paddingBottom: theme.spacing(2),
  },
  gridCell: {
    whiteSpace: 'nowrap',
    width: '100%',
    height: '100%',
    display: 'flex',
    flexDirection: 'column',
    paddingLeft: '1em',
    paddingRight: '1em',
    justifyContent: 'center',
  },
}));

export default function ResultTable() {
  const recordingContext = useContext(RecordingContext);

  const classes = useStyles();

  const result = recordingContext?.activeRecording?.queryOutput;

  if (!result || !result.results) {
    return (
      <Typography style={{ padding: '8px 16px' }} variant="subtitle1">
        No data to show
      </Typography>
    );
  }

  const { labels, types, values } = result.results;

  function formatDate(d: Date) {
    let month = `${d.getMonth() + 1}`;
    let day = `${d.getDate()}`;
    const year = d.getFullYear();

    if (month.length < 2) month = `0${month}`;
    if (day.length < 2) day = `0${day}`;

    return [year, month, day].join('-');
  }

  function format(index: number, entry: unknown): string {
    let datatype = 0;
    if (types) {
      datatype = types[index];
    }
    if (datatype === 12) {
      if (typeof entry === 'number') {
        const date = new Date(Number(entry));
        return formatDate(date);
      }
      const date = new Date(String(entry));
      return formatDate(date);
    }
    return String(entry);
  }

  const STYLE: CSSProperties = {
    width: '100%',
    fontFamily: 'raleway',
    resize: 'none',
  };

  const cache = new CellMeasurerCache({
    defaultWidth: 100,
    fixedHeight: true,
  });

  type CellRendererType = {
    rowIndex: number;
    columnIndex: number;
    style: React.CSSProperties;
    parent: MeasuredCellParent;
  };

  function cellRenderer({
    rowIndex,
    parent,
    columnIndex,
    style,
  }: CellRendererType) {
    const content =
      rowIndex === 0
        ? labels[columnIndex]
        : format(columnIndex, values[rowIndex - 1][columnIndex]);
    return (
      <CellMeasurer
        cache={cache}
        parent={parent}
        key={`${columnIndex}-${rowIndex}`}
        columnIndex={columnIndex}
        rowIndex={rowIndex}
      >
        <div
          style={style}
          key={`${columnIndex}-${rowIndex}`}
          className={classes.gridCell}
        >
          {content}
        </div>
      </CellMeasurer>
    );
  }
  return (
    <div className={classes.tableWrapper}>
      <div
        style={{
          minHeight: 201,
          height: '100%',
          width: '100%',
          paddingBottom: 1,
        }}
      >
        <AutoSizer>
          {({ height, width }) => (
            <MultiGrid
              cellRenderer={cellRenderer}
              columnWidth={cache.columnWidth}
              columnCount={labels.length}
              height={height}
              deferredMeasurementCache={cache}
              rowHeight={48}
              rowCount={values.length + 1}
              scrollToColumn={0}
              scrollToRow={0}
              fixedRowCount={1}
              width={width}
              style={STYLE}
              styleTopRightGrid={{
                fontWeight: 'bold',
                width: '100%',
                backgroundColor: '#404040',
                fontSize: 14,
              }}
              styleBottomRightGrid={{
                outline: 'none',
              }}
              overscanColumnCount={0}
              overscanRowCount={20}
            />
          )}
        </AutoSizer>
      </div>
    </div>
  );
}
  • I was able to find out that the problem lies with the cellmeasurer, removing this made the component load nicely. This leaves the problem of the grid not having dynamic widths though, so is there are any way to fix this? – Tobias Ingebrigt Ørstad Oct 21 '20 at 12:10

0 Answers0