Skip to content

[data grid] Poor performance with TreeData and large dataset #17389

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
amannan-bucs opened this issue Apr 16, 2025 · 11 comments
Open

[data grid] Poor performance with TreeData and large dataset #17389

amannan-bucs opened this issue Apr 16, 2025 · 11 comments
Assignees
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Tree data Related to the data grid Tree data feature performance plan: Pro Impact at least one Pro user support: pro standard Support request from a Pro standard plan user. https://mui.com/legal/technical-support-sla/

Comments

@amannan-bucs
Copy link

amannan-bucs commented Apr 16, 2025

Steps to reproduce

Steps:

  1. Open this link to live example: Codesandbox Demo
  2. Attempt the following interactions:
  • Expand/collapse nodes within the TreeData.
  • Scroll vertically through the dataset.
  • Perform any editing or cell interaction within the grid.
  1. Observe the performance lag and sluggish response times.

Current behavior

The DataGrid becomes significantly slow and unresponsive when interacting with TreeData on large datasets (50,000+ rows), even with virtualization enabled. Actions like toggling expand/collapse and scrolling are particularly affected.

Expected behavior

The grid should remain responsive and fluid during all interactions — including editing, scrolling, and expanding TreeData — even with large datasets. This is crucial for our production use case, where users frequently work with tens of thousands of records in real time.

Context

We are building a highly interactive data table that allows users to view, edit, and manipulate large datasets seamlessly. Performance is a critical factor for usability, and current slowness is a blocker in adopting this component for our needs. We expect virtualization to handle these volumes more efficiently.

Your environment

npx @mui/envinfo
  System:
    OS: Windows 11 10.0.22631
  Binaries:
    Node: 20.12.0 - C:\Program Files\nodejs\node.EXE
    npm: 10.5.0 - C:\Program Files\nodejs\npm.CMD
    pnpm: Not Found
  Browsers:
    Chrome: Not Found
    Edge: Chromium (135.0.3179.73)
  npmPackages:
    @mui/lab: ^6.0.0-beta.21 => 6.0.0-beta.21 
    @mui/styled-engine-sc: ^6.3.0 => 6.3.0 
    @mui/x-data-grid: ^7.23.5 => 7.23.5 
    @mui/x-data-grid-pro: ^7.23.5 => 7.23.5 
    @mui/x-date-pickers: ^7.23.3 => 7.23.3
    @mui/x-tree-view: ^7.23.2 => 7.23.2
    styled-components: latest => 6.1.13

Search keywords: data-grid-pro, data-grid-treedata, performance, large-dataset

Order ID: 102733

@amannan-bucs amannan-bucs added bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 16, 2025
@github-actions github-actions bot added component: data grid This is the name of the generic UI component, not the React module! support: pro standard Support request from a Pro standard plan user. https://mui.com/legal/technical-support-sla/ labels Apr 16, 2025
@arminmeh arminmeh changed the title Performance Issue: MUI DataGrid Pro is Slow with TreeData and Large Dataset (50K+ rows) – Especially When Expanding Nodes and Scrolling (Virtualization Enabled) [data grid] Poor performance with TreeData and large dataset Apr 16, 2025
@arminmeh arminmeh added performance plan: Pro Impact at least one Pro user feature: Tree data Related to the data grid Tree data feature and removed bug 🐛 Something doesn't work labels Apr 16, 2025
@arminmeh
Copy link
Contributor

@amannan-bucs
I will investigate this further, but I am noticing that commenting out columns and groupingColDef props improves the performance a lot.
I would say that the problem is probably related to the custom cell renderers (group and actions).

@amannan-bucs
Copy link
Author

Hi @arminmeh,

Thanks for looking into this!
You're right that removing columns and groupingColDef does improve performance a bit (not 100%)—but unfortunately, those are essential parts of our implementation. Custom cell renderers (particularly for grouping and actions) are necessary to meet our UI/UX and business requirements, so we can't remove them. Also, please note that in the actual case, I need to have such kind of more renderers to fulfil the business requirements.

Given that, I'd really appreciate any guidance on optimizing performance with these props in place. Are there known best practices or workarounds for improving render efficiency when using custom renderers with treeData? If there's anything that can help in this matter, we'd love to hear about it.

Looking forward to any further insights you uncover.

@michelengelen
Copy link
Member

michelengelen commented Apr 22, 2025

So, the main problem here is that you use state (isExpanded) to store the id of the expanded row. This triggers a full rerender and leads to the performance hit.

If you extract the grouping cell render:

const RenderGroupingCell = (params: GridRenderCellParams) => {
  const { id, rowNode, value } = params;
  const apiRef = useGridApiContext();
  const [isExpanded, setIsExpanded] = React.useState(
    rowNode.type === 'group' && rowNode?.childrenExpanded,
  );

  const handleToggle = React.useCallback(() => {
    setIsExpanded((prev) => !prev);
    apiRef.current?.setRowChildrenExpansion(id, !isExpanded);
  }, [apiRef, isExpanded]);

  return (
    <FlexBox alignItems={'center'} flex={1} margin={'0px -10px'} height={'100%'}>
      {rowNode.type === 'group' && (
        <IconButton onClick={handleToggle}>
          <ExpandMoreIcon
            sx={(theme) => ({
              fontSize: 20,
              transform: `rotateZ(${isExpanded ? 0 : -90}deg)`,
              transition: theme.transitions.create('transform', {
                duration: theme.transitions.duration.shortest,
              }),
            })}
            fontSize="small"
          />
        </IconButton>
      )}

      <Typography fontSize={14} sx={{ ml: 1 }} fontWeight={600}>
        {value}
      </Typography>
    </FlexBox>
  );
};

... and use IconButton instead of GridActionCellItem ... you can then listen on the 'rowExpansionChange' event with gridApiRef.current?.subscribeEvent(...) and store it in a ref instead.

With this the bottleneck should be gone

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 22, 2025
@amannan-bucs
Copy link
Author

@michelengelen I've implemented the solution you suggested in your last comment. Unfortunately, it hasn't significantly improved the performance lag we're experiencing.

We're using expandedRowId because our grid is editable. When a row enters edit mode or an update is made, the expanded row collapses due to a re-render happening behind the scenes. To avoid this behavior, we need to explicitly manage the expanded state of the group.

Please take a look at the updated code in the live demo, which reflects your recommendations. Since the performance hasn't improved noticeably, I'd appreciate it if you could take another look and let me know if there are any other potential bottlenecks or optimizations we might be missing.

Thanks!

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 24, 2025
@amannan-bucs
Copy link
Author

Since Codesandbox Demo is not working, I have added the code in another GitHub repository for you to have a look. Please take a look at following repo:
https://github.com/amannan-bucs/dg-treedata-performance-demo

@michelengelen
Copy link
Member

The sandbox was working for me.
Other than the suggested improvements here are some more you can incorporate as well:

const RenderGroupingCell = (params: GridRenderCellParams) => {
  const { id, rowNode, value } = params;
  const apiRef = useGridApiContext();
  const [isExpanded, setIsExpanded] = React.useState(
    rowNode.type === 'group' && rowNode?.childrenExpanded,
  );

  const handleToggle = React.useCallback(() => {
    setIsExpanded((prev) => !prev);
    apiRef.current?.setRowChildrenExpansion(id, !isExpanded);
  }, [apiRef, isExpanded]);

  return (
    <FlexBox alignItems={'center'} flex={1} margin={'0px -10px'} height={'100%'}>
      {rowNode.type === 'group' && (
        <IconButton onClick={handleToggle}>
          <ExpandMoreIcon
            sx={(theme) => ({
              fontSize: 20,
              transform: `rotateZ(${isExpanded ? 0 : -90}deg)`,
              transition: theme.transitions.create('transform', {
                duration: theme.transitions.duration.shortest,
              }),
            })}
            fontSize="small"
          />
        </IconButton>
      )}

      <Typography fontSize={14} sx={{ ml: 1 }} fontWeight={600}>
        {value}
      </Typography>
    </FlexBox>
  );
};


// extract the grouping column definition, pinnedColumns and getTreeDataPath
// prop values to create stable references
const MDR_GROUPING_COL_DEF = {
  headerName: 'Commodity',
  minWidth: 320,
  flex: 1,
  sortable: true,
  hideDescendantCount: true,
  hideable: false,
  leafField: 'commodity',
  renderCell: RenderGroupingCell,
};

const pinnedColumns = {
  right: ['actions'],
};

const getTreeDataPath: DataGridProProps['getTreeDataPath'] = (row) => {
  return [row.commodity, row.id];
};

export default function DataGridProDemo() {
  const gridApiRef = useGridApiRef();
  const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>({});
  const expandedTreeRowId = React.useRef<GridRowId | null>(null);
  const { data, loading } = useDemoData({
    dataSet: 'Commodity',
    rowLength: 95000,
    editable: true,
  });

  // use ref instead of state to decrease number of re-renders due to state updates
  React.useEffect(() => {
    return gridApiRef.current?.subscribeEvent('rowExpansionChange', (params) => {
      const { id } = params;
      const rowNode = gridRowNodeSelector(gridApiRef, id);
      if (rowNode.type === 'group') {
        expandedTreeRowId.current = rowNode?.isExpanded ? id : null;
      }
    });
  }, [gridApiRef]);

  // wrap it in useCallback to make the reference more stable
  const checkIsGroupExpandedByDefault: DataGridProProps['isGroupExpandedByDefault'] =
    React.useCallback(
      (node: GridGroupNode) => expandedTreeRowId.current === node.id,
      [expandedTreeRowId.current],
    );

  return (
    <Box sx={{ height: 520, width: '100%' }}>
      <DataGridPro
        {...data}
        treeData
        checkboxSelection
        disableRowSelectionOnClick
        apiRef={gridApiRef}
        columns={data.columns}
        loading={loading}
        getTreeDataPath={getTreeDataPath}
        isGroupExpandedByDefault={checkIsGroupExpandedByDefault}
        groupingColDef={MDR_GROUPING_COL_DEF}
        rowModesModel={rowModesModel}
        onRowModesModelChange={setRowModesModel}
        rowHeight={38}
        pinnedColumns={pinnedColumns}
        editMode="row"
      />
    </Box>
  );
}

Could you try that as well?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Apr 24, 2025
@amannan-bucs
Copy link
Author

@michelengelen, most of the improvements you suggested were already implemented in my actual project. I’ve now also applied the remaining suggestions—both in the main project (including similar enhancements across other custom renderers) and in a live CodeSandbox for your reference.

That said, the performance gains are still quite minimal. The grid and tree data remain noticeably slow, even in the test project. Could you please take another look when you have a moment?

Additionally, I created a separate project without any custom renderers, and its performance is noticeably better. However, as mentioned earlier, our actual project requires these custom renderers to meet specific business and UI/UX needs.

Here’s the link to the other project:
https://codesandbox.io/p/devbox/keen-wind-k9kp8f?from-embed=&workspaceId=ws_M4zGUvRFbz1njq8yb1MvGJ

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Apr 25, 2025
@michelengelen
Copy link
Member

@arminmeh could you also have another look if we can improve something on the demo?

@arminmeh
Copy link
Contributor

arminmeh commented May 5, 2025

I have extracted more things outside of the component to make the references more stable and avoid explicit memoization.
I have also updated the child count cell renderer to be aligned with our demos.

Performance is still not perfect, but I think that it has improved a lot
@amannan-bucs
can you check this demo
https://codesandbox.io/p/sandbox/summer-meadow-zmkjhp?file=%2Fsrc%2FDemo.tsx
and let us know if this helps?

@arminmeh arminmeh added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels May 5, 2025
@amannan-bucs
Copy link
Author

Hi @arminmeh , Thanks for looking into this. I’ve reviewed the improvements you’ve made and incorporated them into our actual project. Unfortunately, as you also pointed out, the performance is still not satisfactory.

Our real implementation includes additional features that aren't present in the demo but are necessary to meet our UI/UX and business requirements. Given the current performance limitations, we’re unable deliver the feature with these performance lags.

Is there any alternative approach we could explore to achieve significantly better performance when using DataGrid with tree data/grouping on larger datasets?

@github-actions github-actions bot removed the status: waiting for author Issue with insufficient information label May 6, 2025
@github-actions github-actions bot added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 6, 2025
@cherniavskii cherniavskii self-assigned this May 6, 2025
@michelengelen michelengelen removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 9, 2025
@amannan-bucs
Copy link
Author

Any update on this please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Tree data Related to the data grid Tree data feature performance plan: Pro Impact at least one Pro user support: pro standard Support request from a Pro standard plan user. https://mui.com/legal/technical-support-sla/
Projects
None yet
Development

No branches or pull requests

4 participants