Skip to content

[data grid] Improve the performance of stringify #19414

@baron04

Description

@baron04

Steps to reproduce

Steps:

  1. Use ThemeProvider to customize the theme. The theme variable is defined inside the component.
  2. The theme object includes a React element.

Demo.tsx

import { DataGridPro } from '@mui/x-data-grid-pro';
import { useDemoData } from '@mui/x-data-grid-generator';
import { createTheme, ThemeProvider } from '@mui/material';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';

export default function Demo() {
  const { data, loading } = useDemoData({
    dataSet: 'Commodity',
    rowLength: 1000,
    editable: true,
  });

  const theme = createTheme({
    components: {
      MuiCheckbox: {
        defaultProps: {
          icon: <CheckCircleIcon />,
        },
      },
    },
  });

  return (
    <ThemeProvider theme={theme}>
      <DataGridPro
        {...data}
        pagination
        loading={loading}
        initialState={{
          pagination: {
            paginationModel: { pageSize: 5 },
          },
        }}
        pageSizeOptions={[5]}
      />
    </ThemeProvider>
  );
}

Current behavior

source code: https://github.com/mui/mui-x/blob/master/packages/x-internals/src/hash/stringify.ts

Executing the stringify function within the DataGrid is slow when the theme object contains React Elements. This is because a React Element (or more specifically, its underlying FiberNode) is a large object, which leads to slow execution and the generation of a large string. Additionally, the execution speed of the hash function will also be slow.

Based on my testing, the execution of the hash and stringify functions takes 10ms even for the simplest demo. For more complex pages, the execution time increases severalfold. This multiplicative effect is also observed on pages with multiple DataGrid components. This leads to slow rendering of the DataGrid component, which in turn results in poor page load performance.

Expected behavior

I suggest changing the stringify implementation. During JSON.stringify, if a value is a React element, we should return undefined to omit it from the result. This would prevent the expensive serialization of the React element. While this should improve performance, I’m not sure what potential side effects it might introduce.

+ import * as React from 'react';

export function stringify(input: object | string | number | null) {
  const seen = new WeakSet();
  return JSON.stringify(input, (_, v) => {
    // https://github.com/mui/mui-x/issues/17855
    if (
      (typeof window !== 'undefined' && v === window) ||
      (typeof document !== 'undefined' && v === document)
    ) {
      return v.toString();
    }
    if (v !== null && typeof v === 'object') {
+     if (React.isValidElement(v)) {
+       return;
+     }
      if (seen.has(v)) {
        return null;
      }
      seen.add(v);
    }
    return v;
  });
}

Context

No response

Your environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    scope: data gridChanges related to the data grid.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions