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