How to Optimize DevExtreme DataGrid Performance with 6000+ Records and 160+ Columns in React?

I have implemented a data table using the DevExtreme DataGrid in React. The table has over 6000 records and more than 160 columns. Here’s how it works:

Initially, I load only the column names.
Upon clicking a button, all the records are fetched from an API.
The table uses virtual scrolling for better performance.
However, I’m facing an issue where skeleton loaders appear both above and below the viewport while scrolling, which creates a weird visual effect. Here’s a simplified version of my code:

import React, { memo } from "react";
import DataGrid, {
  Column,
  ColumnChooser,
  Export,
  Paging,
  Scrolling,
  SearchPanel,
  Selection,
  Sorting,
  Summary,
  TotalItem
} from "devextreme-react/data-grid";
import PropTypes from "prop-types"; // Import PropTypes

const DataGridComponent = memo((props) => {

  const {
    data,
    keyExpr,
    onSelectionChanged,
    selectedRows,
    columns,
    stickyIndex,
    summaryItems,
    extraColumn,
    onIconClick,
    cellRender,
    height
  } = props;

  // Memoize data to avoid re-renders on each row selection change
  const memoizedData = React.useMemo(() => data, [data]);

  // Memoize columns (if an extra column is provided)
  const memoizedColumns = React.useMemo(() => {
    return extraColumn ? [extraColumn, ...columns] : columns;
  }, [extraColumn, columns]);

  const memoizedCellRender = React.useCallback((e, col) => {
    if (cellRender) {
      return cellRender(e, col);
    }
  }, [cellRender]);

  // Detect if the screen is mobile
  const isMobile = React.useMemo(() => window.innerWidth <= 768, []);

  return (
    <div style={{ height: "100%", display: "flex", flexDirection: "column", padding: "10px 0" }}>
      <DataGrid
        dataSource={memoizedData}
        animation={{ enabled: false }}
        keyExpr={keyExpr}
        showBorders={true}
        allowColumnResizing={false}
        columnAutoWidth={true}
        height={height}
        onSelectionChanged={(e) => onSelectionChanged(e?.selectedRowKeys)}
        selectedRowKeys={selectedRows}
        showColumnLines={true}
        loadPanel={{
          enabled: false,
          showIndicator: true,
        }}
      >
        <ColumnChooser enabled />
        <Selection mode="multiple" showCheckBoxesMode="always" />
        <Scrolling mode="virtual" />
        <Paging enabled={false} />
        <Sorting mode="multiple" />
        <SearchPanel visible highlightCaseSensitive />
        <Export enabled />

        {Array.isArray(memoizedColumns) && memoizedColumns.map((col, index) => (
          <Column
            key={index}
            fixed={!isMobile && index < stickyIndex} // Disable fixed columns on mobile
            fixedPosition="left"
            dataField={col.accessorKey}
            caption={col.header}
            visible={col.is_visible}
            alignment={col.textAlign}
            allowFiltering={true}
            allowSorting={true}
            cellRender={(e) => memoizedCellRender(e, col)}
          />
        ))}

        <Summary>
          {summaryItems.map((item, index) => (
            <TotalItem
              key={index}
              column={item.column}
              summaryType={item.summaryType}
              displayFormat={item.displayFormat}
              skipEmptyValues={false}
            />
          ))}
        </Summary>
      </DataGrid>
    </div>
  );
});

// Define PropTypes
DataGridComponent.propTypes = {
  data: PropTypes.array,
  keyExpr: PropTypes.string,
  onSelectionChanged: PropTypes.func,
  selectedRows: PropTypes.array,
  columns: PropTypes.array,
  stickyIndex: PropTypes.number,
  summaryItems: PropTypes.array,
  loading: PropTypes.bool,
  onIconClick: PropTypes.func,
  cellRender: PropTypes.func,
};

// Set default props to avoid crashes
DataGridComponent.defaultProps = {
  data: [],
  keyExpr: "diamond_id",
  onSelectionChanged: () => { },
  selectedRows: [],
  columns: [],
  stickyIndex: 0,
  summaryItems: [],
  loading: true,
  onIconClick: () => { },
  cellRender: null
};

export default DataGridComponent;

Key Points:
I’m using virtual scrolling mode.
Skeleton loaders show up awkwardly during scrolling.
The issue is noticeable because of the large dataset and many columns.

What I’ve Tried:
Disabling animations using animation: { enabled: false }.
Optimizing data and column rendering using useMemo.

Questions:

  • Is there a way to prevent skeleton loaders from appearing above and below the viewport while scrolling?
  • Are there additional optimizations for handling large datasets and many columns with the DevExtreme DataGrid?

Any suggestions or best practices for improving the scrolling behavior and overall performance would be greatly appreciated!

What I Tried:

  1. I disabled animations in the DataGrid using animation: { enabled: false }.
  2. I used React.useMemo to optimize the rendering of both data and columns.
  3. I configured the grid to use virtual scrolling with scrolling: { mode: "virtual" }.

What I Expected:
I expected smoother scrolling with no skeleton loaders or rendering artifacts, ensuring a seamless user experience even with large datasets and many columns.

What Actually Happened:
Despite these optimizations, skeleton loaders still appear above and below the viewport during scrolling, creating a visually unappealing experience.