diff --git a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx
index ff711ab42c48..1b8d2a88a567 100644
--- a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx
+++ b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx
@@ -28,6 +28,7 @@ import {
GridColumnVisibilityModel,
gridColumnPositionsSelector,
gridVisiblePinnedColumnDefinitionsSelector,
+ gridColumnLookupSelector,
} from '../columns';
import { GridGroupingStructure } from '../columnGrouping/gridColumnGroupsInterfaces';
import { gridColumnGroupsUnwrappedModelSelector } from '../columnGrouping/gridColumnGroupsSelector';
@@ -106,6 +107,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => {
const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector);
const renderContext = useGridSelector(apiRef, gridRenderContextColumnsSelector);
const pinnedColumns = useGridSelector(apiRef, gridVisiblePinnedColumnDefinitionsSelector);
+ const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector);
const offsetLeft = computeOffsetLeft(
columnPositions,
renderContext,
@@ -392,7 +394,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => {
firstVisibleColumnIndex,
);
const leftOverflow = hiddenGroupColumns.reduce((acc, field) => {
- const column = apiRef.current.getColumn(field);
+ const column = columnsLookup[field];
return acc + (column.computedWidth ?? 0);
}, 0);
@@ -411,10 +413,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => {
const headerInfo: HeaderInfo = {
groupId,
- width: columnFields.reduce(
- (acc, field) => acc + apiRef.current.getColumn(field).computedWidth,
- 0,
- ),
+ width: columnFields.reduce((acc, field) => acc + columnsLookup[field].computedWidth, 0),
fields: columnFields,
colIndex: columnIndex,
hasFocus,
diff --git a/packages/x-data-grid/src/tests/columnGrouping.DataGrid.test.tsx b/packages/x-data-grid/src/tests/columnGrouping.DataGrid.test.tsx
index d3ee1dd081c5..7d0a1002e2c4 100644
--- a/packages/x-data-grid/src/tests/columnGrouping.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/columnGrouping.DataGrid.test.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
+import * as ReactDOM from 'react-dom';
import { expect } from 'chai';
-import { createRenderer, ErrorBoundary, screen } from '@mui/internal-test-utils';
+import { createRenderer, ErrorBoundary, fireEvent, screen } from '@mui/internal-test-utils';
import { DataGrid, DataGridProps, GridRowModel, GridColDef } from '@mui/x-data-grid';
const isJSDOM = /jsdom/.test(window.navigator.userAgent);
@@ -325,6 +326,56 @@ describe(' - Column grouping', () => {
Array.from(row2Headers).map((header) => header.getAttribute('aria-colindex')),
).to.deep.equal(['1', '2', '3']);
});
+
+ // https://github.com/mui/mui-x/issues/13985
+ it('should not throw when both `columns` and `columnGroupingModel` are updated twice', () => {
+ function Demo() {
+ const [props, setProps] = React.useState<
+ Pick
+ >({
+ columns: [],
+ columnGroupingModel: [],
+ });
+
+ const handleClick = () => {
+ ReactDOM.flushSync(() => {
+ setProps({
+ columns: [{ field: `field_0` }],
+ columnGroupingModel: [{ groupId: 'Group', children: [{ field: `field_0` }] }],
+ });
+ });
+
+ setProps({
+ columns: [{ field: `field_1` }],
+ columnGroupingModel: [{ groupId: 'Group', children: [{ field: `field_1` }] }],
+ });
+ };
+
+ return (
+
+
+
+
+ );
+ }
+ render();
+
+ fireEvent.click(screen.getByRole('button', { name: /Update columns/ }));
+
+ const row1Headers = document.querySelectorAll(
+ '[aria-rowindex="1"] [role="columnheader"]',
+ );
+ const row2Headers = document.querySelectorAll(
+ '[aria-rowindex="2"] [role="columnheader"]',
+ );
+
+ expect(
+ Array.from(row1Headers).map((header) => header.getAttribute('aria-label')),
+ ).to.deep.equal(['Group']);
+ expect(
+ Array.from(row2Headers).map((header) => header.getAttribute('aria-label')),
+ ).to.deep.equal(['field_1']);
+ });
});
// TODO: remove the skip. I failed to test if an error is thrown