Skip to content
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

[data grid] Updating Columns and Column Grouping Simultaneously and Repeatedly throws Runtime Errors #13985

Closed
goldst opened this issue Jul 26, 2024 · 3 comments · Fixed by #14368
Assignees
Labels
component: data grid This is the name of the generic UI component, not the React module! regression A bug, but worse support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/

Comments

@goldst
Copy link

goldst commented Jul 26, 2024

Steps to reproduce

Press the button in the reproductions once:
Reproduction v7: https://codesandbox.io/s/reproduction-column-grouping-v7-6qw5qv?file=/src/Demo.tsx
Reproduction v6: https://codesandbox.io/s/reproduction-column-grouping-v6-d6m28s?file=/src/Demo.tsx
The issue arises when columns and columnGrouping are updated at the same time, at least two times, in a short time period.

Current behavior

Current behavior:
DataGrid throws an error. Depending on the browser and the version:

  • v7:
    • Firefox: apiRef.current.getColumn(...) is undefined
    • Chrome: Cannot read properties of undefined (reading 'computedWidth')
  • v6:
    • Firefox: visibleColumnGroupHeader[0] is undefined
    • Chrome: Cannot read properties of undefined (reading 'columnFields')

Expected behavior

No error, because the provided props are consistent at any point in time.

Context

This bug is blocking our migration from DataGrid v5 to v6. In v5, this worked without problems.
We use this set of features to load and display new columns on request and remove columns that aren't relevant any longer. We can't always ensure that there is only one re-render due to multiple data sources.

We found these issues describing similar bugs. However, none of their PRs fully fix this problem.
#8602, #8492

Patch that solves the error - tested in v6
--- a/hooks/features/columnHeaders/useGridColumnHeaders.js
+++ b/hooks/features/columnHeaders/useGridColumnHeaders.js
@@ -1,20 +1,22 @@
 import _extends from "@babel/runtime/helpers/esm/extends";
+import { styled, useTheme } from '@mui/material/styles';
+import { unstable_useForkRef as useForkRef } from '@mui/utils';
 import * as React from 'react';
 import * as ReactDOM from 'react-dom';
-import { unstable_useForkRef as useForkRef } from '@mui/utils';
-import { styled, useTheme } from '@mui/material/styles';
+import { jsx as _jsx } from "react/jsx-runtime";
 import { defaultMemoize } from 'reselect';
+import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader';
+import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColumnHeaderItem';
 import { useGridSelector } from '../../utils';
+import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
 import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
 import { useGridRootProps } from '../../utils/useGridRootProps';
-import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
-import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColumnHeaderItem';
-import { getFirstColumnIndexToRender, getTotalHeaderHeight } from '../columns/gridColumnsUtils';
 import { useGridVisibleRows } from '../../utils/useGridVisibleRows';
-import { areRenderContextsEqual, getRenderableIndexes } from '../virtualization/useGridVirtualScroller';
+import { gridColumnGroupsUnwrappedModelSelector } from "../columnGrouping/gridColumnGroupsSelector";
+import { gridColumnLookupSelector } from "../columns/gridColumnsSelector";
+import { getFirstColumnIndexToRender, getTotalHeaderHeight } from '../columns/gridColumnsUtils';
 import { gridVirtualizationColumnEnabledSelector } from '../virtualization';
-import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader';
-import { jsx as _jsx } from "react/jsx-runtime";
+import { areRenderContextsEqual, getRenderableIndexes } from '../virtualization/useGridVirtualScroller';
 const GridColumnHeaderRow = styled('div', {
   name: 'MuiDataGrid',
   slot: 'ColumnHeaderRow',
@@ -49,6 +51,9 @@ export const useGridColumnHeaders = props => {
   const [resizeCol, setResizeCol] = React.useState('');
   const apiRef = useGridPrivateApiContext();
   const hasVirtualization = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector);
+  const columnGroupsModel = useGridSelector(apiRef, gridColumnGroupsUnwrappedModelSelector)
+  const lookup = useGridSelector(apiRef, gridColumnLookupSelector)
+
   const rootProps = useGridRootProps();
   const innerRef = React.useRef(null);
   const handleInnerRef = useForkRef(innerRefProp, innerRef);
@@ -239,17 +244,18 @@ export const useGridColumnHeaders = props => {
     } = columnsToRender;
     const columns = [];
     const headerToRender = [];
+
     for (let depth = 0; depth < headerGroupingMaxDepth; depth += 1) {
       var _apiRef$current$unsta, _apiRef$current$unsta2;
       const rowStructure = columnGroupsHeaderStructure[depth];
       const firstColumnFieldToRender = visibleColumns[firstColumnToRender].field;
-      const firstGroupToRender = (_apiRef$current$unsta = apiRef.current.unstable_getColumnGroupPath(firstColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta : null;
+      const firstGroupToRender = columnGroupsModel[firstColumnFieldToRender]?.[depth] ?? null;
       const firstGroupIndex = rowStructure.findIndex(({
         groupId,
         columnFields
       }) => groupId === firstGroupToRender && columnFields.includes(firstColumnFieldToRender));
       const lastColumnFieldToRender = visibleColumns[lastColumnToRender - 1].field;
-      const lastGroupToRender = (_apiRef$current$unsta2 = apiRef.current.unstable_getColumnGroupPath(lastColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta2 : null;
+      const lastGroupToRender = columnGroupsModel[lastColumnFieldToRender]?.[depth] ?? null;
       const lastGroupIndex = rowStructure.findIndex(({
         groupId,
         columnFields
@@ -263,8 +269,8 @@ export const useGridColumnHeaders = props => {
       const hiddenGroupColumns = visibleColumnGroupHeader[0].columnFields.slice(0, firstVisibleColumnIndex);
       const leftOverflow = hiddenGroupColumns.reduce((acc, field) => {
         var _column$computedWidth;
-        const column = apiRef.current.getColumn(field);
-        return acc + ((_column$computedWidth = column.computedWidth) != null ? _column$computedWidth : 0);
+        const column = lookup[field];
+        return acc + ((_column$computedWidth = (column.computedWidth || 0)) != null ? _column$computedWidth : 0);
       }, 0);
       let columnIndex = firstColumnToRender;
       const elements = visibleColumnGroupHeader.map(({
@@ -275,7 +281,7 @@ export const useGridColumnHeaders = props => {
         const tabIndex = columnGroupHeaderTabIndexState !== null && columnGroupHeaderTabIndexState.depth === depth && columnFields.includes(columnGroupHeaderTabIndexState.field) ? 0 : -1;
         const headerInfo = {
           groupId,
-          width: columnFields.reduce((acc, field) => acc + apiRef.current.getColumn(field).computedWidth, 0),
+          width: columnFields.reduce((acc, field) => acc + (lookup[field].computedWidth || 0), 0),
           fields: columnFields,
           colIndex: columnIndex,
           hasFocus,
diff --git a/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js b/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js
index 08108efa42430dc04cce638752bd361311769346..87ffbb34da393f7f2e630db0aef74b581f360c3a 100644
--- a/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js
+++ b/legacy/hooks/features/columnHeaders/useGridColumnHeaders.js
@@ -59,6 +59,7 @@ export var useGridColumnHeaders = function useGridColumnHeaders(props) {
     setResizeCol = _React$useState4[1];
   var apiRef = useGridPrivateApiContext();
   var hasVirtualization = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector);
+  var columnGroupsModel = useGridSelector(apiRef, gridColumnGroupsUnwrappedModelSelector)
   var rootProps = useGridRootProps();
   var innerRef = React.useRef(null);
   var handleInnerRef = useForkRef(innerRefProp, innerRef);
@@ -273,14 +274,14 @@ export var useGridColumnHeaders = function useGridColumnHeaders(props) {
       var _apiRef$current$unsta, _apiRef$current$unsta2;
       var rowStructure = columnGroupsHeaderStructure[depth];
       var firstColumnFieldToRender = visibleColumns[firstColumnToRender].field;
-      var firstGroupToRender = (_apiRef$current$unsta = apiRef.current.unstable_getColumnGroupPath(firstColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta : null;
+      const firstGroupToRender = columnGroupsModel[firstColumnFieldToRender]?.[depth] ?? null;
       var firstGroupIndex = rowStructure.findIndex(function (_ref4) {
         var groupId = _ref4.groupId,
           columnFields = _ref4.columnFields;
         return groupId === firstGroupToRender && columnFields.includes(firstColumnFieldToRender);
       });
       var lastColumnFieldToRender = visibleColumns[lastColumnToRender - 1].field;
-      var lastGroupToRender = (_apiRef$current$unsta2 = apiRef.current.unstable_getColumnGroupPath(lastColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta2 : null;
+      const lastGroupToRender = columnGroupsModel[lastColumnFieldToRender]?.[depth] ?? null;
       var lastGroupIndex = rowStructure.findIndex(function (_ref5) {
         var groupId = _ref5.groupId,
           columnFields = _ref5.columnFields;

If it helps to solve this quicker, we can open a PR based on the changes shown in the diff. Let me know.

Your environment

bunx @mui/envinfo
  System:
    OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (20) x64 12th Gen Intel(R) Core(TM) i7-12800H
    Memory: 11.57 GB / 15.46 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
    Yarn: 1.22.19 - /mnt/c/Users/lgoldstein/AppData/Roaming/npm/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.1/bin/npm
    pnpm: 9.6.0 - /mnt/c/Users/lgoldstein/AppData/Roaming/npm/pnpm
    bun: 1.1.9 - ~/.bun/bin/bun
  Managers:
    Apt: 2.4.11 - /usr/bin/apt
  Utilities:
    Git: 2.34.1 - /usr/bin/git
    FFmpeg: 4.4.2 - /usr/bin/ffmpeg
    Curl: 7.81.0 - /usr/bin/curl
    OpenSSL: 3.0.2 - /usr/bin/openssl
  Virtualization:
    Docker: 25.0.1 - /usr/bin/docker
  IDEs:
    Nano: 6.2 - /usr/bin/nano
    VSCode: 1.91.1 - /root/.vscode-server/bin/f1e16e1e6214d7c44d078b1f0607b2388f29d729/bin/remote-cli/code
    Vim: 8.2 - /usr/bin/vim
  Languages:
    Bash: 5.1.16 - /usr/bin/bash
    Perl: 5.34.0 - /usr/bin/perl
    Python3: 3.10.12 - /usr/bin/python3
  Browsers:
    Chrome: 121.0.6167.85

Search keywords: Columns, column grouping, multiple re-renders
Order ID: 72553
Renewed Order ID: 95800

@goldst goldst added bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jul 26, 2024
@github-actions github-actions bot added the component: data grid This is the name of the generic UI component, not the React module! label Jul 26, 2024
@goldst goldst changed the title Updating Columns and Column Grouping Simultaneously and Repeatedly throws Runtime Errors [DataGrid] Updating Columns and Column Grouping Simultaneously and Repeatedly throws Runtime Errors Jul 26, 2024
@michelengelen michelengelen changed the title [DataGrid] Updating Columns and Column Grouping Simultaneously and Repeatedly throws Runtime Errors [data grid] Updating Columns and Column Grouping Simultaneously and Repeatedly throws Runtime Errors Jul 29, 2024
@michelengelen michelengelen added regression A bug, but worse support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/ and removed bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jul 29, 2024
@michelengelen
Copy link
Member

Hey @goldst ... I can confirm this and will add this to the board for the team to have a look!

@github-project-automation github-project-automation bot moved this to 🆕 Needs refinement in MUI X Data Grid Jul 29, 2024
@goldst
Copy link
Author

goldst commented Aug 23, 2024

Thank you @michelengelen. In case it helps: Since creating the bug, we renewed our license. Our new order ID is 95800.
We still look forward to a fix because using the patch on our end is a big pain point.

@cherniavskii cherniavskii moved this from 🆕 Needs refinement to 🔖 Ready in MUI X Data Grid Aug 27, 2024
@cherniavskii cherniavskii self-assigned this Aug 27, 2024
@cherniavskii cherniavskii moved this from 🔖 Ready to 🏗 In progress in MUI X Data Grid Aug 28, 2024
@cherniavskii cherniavskii moved this from 🏗 In progress to 👀 In review in MUI X Data Grid Aug 28, 2024
Copy link

github-actions bot commented Sep 2, 2024

⚠️ This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@goldst: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

@DanailH DanailH moved this from 👀 In review to ✅ Done in MUI X Data Grid Nov 1, 2024
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! regression A bug, but worse support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants