Skip to content

Commit

Permalink
[DataGrid] Avoid <GridRoot /> double-render pass on mount in SPA mo…
Browse files Browse the repository at this point in the history
…de (#15648)

Co-authored-by: Andrew Cherniavskyi <[email protected]>
  • Loading branch information
lauri865 and cherniavskii authored Feb 5, 2025
1 parent e176896 commit ad55b60
Show file tree
Hide file tree
Showing 58 changed files with 728 additions and 422 deletions.
7 changes: 7 additions & 0 deletions docs/data/data-grid/events/events.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@
"params": "ElementSize",
"event": "MuiEvent<{}>"
},
{
"projects": ["x-data-grid", "x-data-grid-pro", "x-data-grid-premium"],
"name": "rootMount",
"description": "Fired when rootElementRef.current becomes available.",
"params": "HTMLElement",
"event": "MuiEvent<{}>"
},
{
"projects": ["x-data-grid", "x-data-grid-pro", "x-data-grid-premium"],
"name": "rowClick",
Expand Down
7 changes: 3 additions & 4 deletions docs/data/data-grid/filtering-recipes/FilteredRowCount.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,14 @@ export default function FilteredRowCount() {

const getFilteredRowsCount = React.useCallback(
(filterModel) => {
const rowIds = apiRef.current?.getAllRowIds();
const filterState = apiRef.current?.getFilterState(filterModel);
if (!filterState) {
if (!rowIds || !filterState) {
return 0;
}

const { filteredRowsLookup } = filterState;
return Object.keys(filteredRowsLookup).filter(
(rowId) => filteredRowsLookup[rowId] === true,
).length;
return rowIds.filter((rowId) => filteredRowsLookup[rowId] !== false).length;
},
[apiRef],
);
Expand Down
7 changes: 3 additions & 4 deletions docs/data/data-grid/filtering-recipes/FilteredRowCount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,14 @@ export default function FilteredRowCount() {

const getFilteredRowsCount = React.useCallback(
(filterModel: GridFilterModel) => {
const rowIds = apiRef.current?.getAllRowIds();
const filterState = apiRef.current?.getFilterState(filterModel);
if (!filterState) {
if (!rowIds || !filterState) {
return 0;
}

const { filteredRowsLookup } = filterState;
return Object.keys(filteredRowsLookup).filter(
(rowId) => filteredRowsLookup[rowId] === true,
).length;
return rowIds.filter((rowId) => filteredRowsLookup[rowId] !== false).length;
},
[apiRef],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ Below are described the steps you need to make to migrate from v7 to v8.
+const output = useGridSelector(apiRef, selector, arguments, equals);
```

- The `filteredRowsLookup` object of the filter state does not contain `true` values anymore. If the row is filtered out, the value is `false`. Otherwise, the row id is not present in the object.
This change only impacts you if you relied on `filteredRowsLookup` to get ids of filtered rows. In this case,use `gridDataRowIdsSelector` selector to get row ids and check `filteredRowsLookup` for `false` values:

```diff
const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);
-const filteredRowIds = Object.keys(filteredRowsLookup).filter((rowId) => filteredRowsLookup[rowId] === true);
+const rowIds = gridDataRowIdsSelector(apiRef);
+const filteredRowIds = rowIds.filter((rowId) => filteredRowsLookup[rowId] !== false);
```

- The `visibleRowsLookup` state does not contain `true` values anymore. If the row is not visible, the value is `false`. Otherwise, the row id is not present in the object:
```diff
const visibleRowsLookup = gridVisibleRowsLookupSelector(apiRef);
-const isRowVisible = visibleRowsLookup[rowId] === true;
+const isRowVisible = visibleRowsLookup[rowId] !== false;
```

### Other exports

- `ariaV8` experimental flag is removed. It's now the default behavior.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const configuration = {
},
};
const releaseInfo = getReleaseInfo();
const watermark = <Watermark packageName="x-data-grid-premium" releaseInfo={releaseInfo} />;

let dataGridPremiumPropValidators: PropValidator<DataGridPremiumProcessedProps>[];

Expand All @@ -47,6 +48,7 @@ const DataGridPremiumRaw = forwardRef(function DataGridPremium<R extends GridVal
if (process.env.NODE_ENV !== 'production') {
validateProps(props, dataGridPremiumPropValidators);
}

return (
<GridContextProvider privateApiRef={privateApiRef} configuration={configuration} props={props}>
<GridRoot
Expand All @@ -56,7 +58,7 @@ const DataGridPremiumRaw = forwardRef(function DataGridPremium<R extends GridVal
{...props.slotProps?.root}
ref={ref}
>
<Watermark packageName="x-data-grid-premium" releaseInfo={releaseInfo} />
{watermark}
</GridRoot>
</GridContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ export const useDataGridPremiumComponent = (
/**
* Register all state initializers here.
*/
useGridInitializeState(dimensionsStateInitializer, apiRef, props);
useGridInitializeState(headerFilteringStateInitializer, apiRef, props);
useGridInitializeState(rowGroupingStateInitializer, apiRef, props);
useGridInitializeState(aggregationStateInitializer, apiRef, props);
Expand All @@ -143,11 +142,12 @@ export const useDataGridPremiumComponent = (
useGridInitializeState(densityStateInitializer, apiRef, props);
useGridInitializeState(columnReorderStateInitializer, apiRef, props);
useGridInitializeState(columnResizeStateInitializer, apiRef, props);
useGridInitializeState(rowsMetaStateInitializer, apiRef, props);
useGridInitializeState(columnMenuStateInitializer, apiRef, props);
useGridInitializeState(columnGroupsStateInitializer, apiRef, props);
useGridInitializeState(virtualizationStateInitializer, apiRef, props);
useGridInitializeState(dataSourceStateInitializer, apiRef, props);
useGridInitializeState(dimensionsStateInitializer, apiRef, props);
useGridInitializeState(rowsMetaStateInitializer, apiRef, props);
useGridInitializeState(listViewStateInitializer, apiRef, props);

useGridRowGrouping(apiRef, props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export const useGridAggregation = (
const currentModel = gridAggregationModelSelector(apiRef);
if (currentModel !== model) {
apiRef.current.setState(mergeStateWithAggregationModel(model));
apiRef.current.forceUpdate();
}
},
[apiRef],
Expand Down Expand Up @@ -147,7 +146,6 @@ export const useGridAggregation = (

// Re-apply the column hydration to wrap / unwrap the aggregated columns
if (!areAggregationRulesEqual(rulesOnLastColumnHydration, aggregationRules)) {
apiRef.current.caches.aggregation.rulesOnLastColumnHydration = aggregationRules;
apiRef.current.requestPipeProcessorsApplication('hydrateColumns');
}
}, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export const useGridAggregationPreProcessors = (
});

rulesOnLastColumnHydration.current = aggregationRules;

apiRef.current.caches.aggregation.rulesOnLastColumnHydration = aggregationRules;

return columnsState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
isNavigationKey,
serializeCellValue,
useGridRegisterPipeProcessor,
useGridVisibleRows,
} from '@mui/x-data-grid-pro/internals';
import {
useGridApiEventHandler,
Expand All @@ -26,7 +25,6 @@ import {
gridFocusCellSelector,
GridCellParams,
GRID_REORDER_COL_DEF,
useGridSelector,
gridSortedRowIdsSelector,
gridDimensionsSelector,
} from '@mui/x-data-grid-pro';
Expand Down Expand Up @@ -64,13 +62,10 @@ export const useGridCellSelection = (
>,
) => {
const hasRootReference = apiRef.current.rootElementRef.current !== null;
const visibleRows = useGridVisibleRows(apiRef, props);
const cellWithVirtualFocus = React.useRef<GridCellCoordinates>(null);
const lastMouseDownCell = React.useRef<GridCellCoordinates>(null);
const mousePosition = React.useRef<{ x: number; y: number }>(null);
const autoScrollRAF = React.useRef<number>(null);
const sortedRowIds = useGridSelector(apiRef, gridSortedRowIdsSelector);
const dimensions = useGridSelector(apiRef, gridDimensionsSelector);
const totalHeaderHeight = getTotalHeaderHeight(apiRef, props);

const ignoreValueFormatterProp = props.ignoreValueFormatterDuringExport;
Expand Down Expand Up @@ -145,6 +140,7 @@ export const useGridCellSelection = (
}

const visibleColumns = apiRef.current.getVisibleColumns();
const visibleRows = getVisibleRows(apiRef);
const rowsInRange = visibleRows.rows.slice(finalStartRowIndex, finalEndRowIndex + 1);
const columnsInRange = visibleColumns.slice(finalStartColumnIndex, finalEndColumnIndex + 1);

Expand All @@ -161,7 +157,7 @@ export const useGridCellSelection = (

apiRef.current.setCellSelectionModel(newModel);
},
[apiRef, visibleRows.rows],
[apiRef],
);

const getSelectedCellsAsArray = React.useCallback<
Expand Down Expand Up @@ -292,6 +288,8 @@ export const useGridCellSelection = (
return;
}

const dimensions = gridDimensionsSelector(apiRef.current.state);

const { x: mouseX, y: mouseY } = mousePosition.current;
const { width, height: viewportOuterHeight } = dimensions.viewportOuterSize;
const height = viewportOuterHeight - totalHeaderHeight;
Expand Down Expand Up @@ -331,7 +329,7 @@ export const useGridCellSelection = (
}

autoScroll();
}, [apiRef, dimensions, totalHeaderHeight]);
}, [apiRef, totalHeaderHeight]);

const handleCellMouseOver = React.useCallback<GridEventListener<'cellMouseOver'>>(
(params, event) => {
Expand All @@ -354,6 +352,7 @@ export const useGridCellSelection = (
return;
}

const dimensions = gridDimensionsSelector(apiRef.current.state);
const { x, y } = virtualScrollerRect;
const { width, height: viewportOuterHeight } = dimensions.viewportOuterSize;
const height = viewportOuterHeight - totalHeaderHeight;
Expand All @@ -378,7 +377,7 @@ export const useGridCellSelection = (
stopAutoScroll();
}
},
[apiRef, startAutoScroll, stopAutoScroll, totalHeaderHeight, dimensions],
[apiRef, startAutoScroll, stopAutoScroll, totalHeaderHeight],
);

const handleCellClick = useEventCallback<
Expand Down Expand Up @@ -438,6 +437,7 @@ export const useGridCellSelection = (
endColumnIndex -= 1;
}

const visibleRows = getVisibleRows(apiRef);
if (endRowIndex < 0 || endRowIndex >= visibleRows.rows.length) {
return;
}
Expand Down Expand Up @@ -490,6 +490,7 @@ export const useGridCellSelection = (

const addClassesToCells = React.useCallback<GridPipeProcessor<'cellClassName'>>(
(classes, { id, field }) => {
const visibleRows = getVisibleRows(apiRef);
if (!visibleRows.range || !apiRef.current.isCellSelected(id, field)) {
return classes;
}
Expand Down Expand Up @@ -538,7 +539,7 @@ export const useGridCellSelection = (

return newClasses;
},
[apiRef, visibleRows.range, visibleRows.rows],
[apiRef],
);

const canUpdateFocus = React.useCallback<GridPipeProcessor<'canUpdateFocus'>>(
Expand Down Expand Up @@ -566,6 +567,7 @@ export const useGridCellSelection = (
if (apiRef.current.getSelectedCellsAsArray().length <= 1) {
return value;
}
const sortedRowIds = gridSortedRowIdsSelector(apiRef.current.state);
const cellSelectionModel = apiRef.current.getCellSelectionModel();
const unsortedSelectedRowIds = Object.keys(cellSelectionModel);
const sortedSelectedRowIds = sortedRowIds.filter((id) =>
Expand Down Expand Up @@ -594,7 +596,7 @@ export const useGridCellSelection = (
}, '');
return copyData;
},
[apiRef, ignoreValueFormatter, clipboardCopyCellDelimiter, sortedRowIds],
[apiRef, ignoreValueFormatter, clipboardCopyCellDelimiter],
);

useGridRegisterPipeProcessor(apiRef, 'isCellSelected', checkIfCellIsSelected);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { RefObject } from '@mui/x-internals/types';
import {
GridRowId,
GridRowTreeConfig,
GridFilterState,
GridFilterModel,
Expand Down Expand Up @@ -80,9 +79,9 @@ export const filterRowTreeFromGroupingColumns = (
params: FilterRowTreeFromTreeDataParams,
): Omit<GridFilterState, 'filterModel'> => {
const { apiRef, rowTree, isRowMatchingFilters, filterModel } = params;
const filteredRowsLookup: Record<GridRowId, boolean> = {};
const filteredChildrenCountLookup: Record<GridRowId, number> = {};
const filteredDescendantCountLookup: Record<GridRowId, number> = {};
const filteredRowsLookup: GridFilterState['filteredRowsLookup'] = {};
const filteredChildrenCountLookup: GridFilterState['filteredChildrenCountLookup'] = {};
const filteredDescendantCountLookup: GridFilterState['filteredDescendantCountLookup'] = {};
const filterCache = {};

const filterTreeNode = (
Expand Down Expand Up @@ -142,7 +141,9 @@ export const filterRowTreeFromGroupingColumns = (
}
}

filteredRowsLookup[node.id] = isPassingFiltering;
if (!isPassingFiltering) {
filteredRowsLookup[node.id] = false;
}

if (!isPassingFiltering) {
return 0;
Expand Down
4 changes: 3 additions & 1 deletion packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const configuration = {
},
};
const releaseInfo = getReleaseInfo();
const watermark = <Watermark packageName="x-data-grid-pro" releaseInfo={releaseInfo} />;

const DataGridProRaw = forwardRef(function DataGridPro<R extends GridValidRowModel>(
inProps: DataGridProProps<R>,
Expand All @@ -34,6 +35,7 @@ const DataGridProRaw = forwardRef(function DataGridPro<R extends GridValidRowMod
if (process.env.NODE_ENV !== 'production') {
validateProps(props, propValidatorsDataGridPro);
}

return (
<GridContextProvider privateApiRef={privateApiRef} configuration={configuration} props={props}>
<GridRoot
Expand All @@ -43,7 +45,7 @@ const DataGridProRaw = forwardRef(function DataGridPro<R extends GridValidRowMod
{...props.slotProps?.root}
ref={ref}
>
<Watermark packageName="x-data-grid-pro" releaseInfo={releaseInfo} />
{watermark}
</GridRoot>
</GridContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export const useDataGridProComponent = (
/**
* Register all state initializers here.
*/
useGridInitializeState(dimensionsStateInitializer, apiRef, props);
useGridInitializeState(headerFilteringStateInitializer, apiRef, props);
useGridInitializeState(rowSelectionStateInitializer, apiRef, props);
useGridInitializeState(detailPanelStateInitializer, apiRef, props);
Expand All @@ -128,11 +127,12 @@ export const useDataGridProComponent = (
useGridInitializeState(densityStateInitializer, apiRef, props);
useGridInitializeState(columnReorderStateInitializer, apiRef, props);
useGridInitializeState(columnResizeStateInitializer, apiRef, props);
useGridInitializeState(rowsMetaStateInitializer, apiRef, props);
useGridInitializeState(columnMenuStateInitializer, apiRef, props);
useGridInitializeState(columnGroupsStateInitializer, apiRef, props);
useGridInitializeState(virtualizationStateInitializer, apiRef, props);
useGridInitializeState(dataSourceStateInitializer, apiRef, props);
useGridInitializeState(dimensionsStateInitializer, apiRef, props);
useGridInitializeState(rowsMetaStateInitializer, apiRef, props);
useGridInitializeState(listViewStateInitializer, apiRef, props);

useGridHeaderFiltering(apiRef, props);
Expand Down
8 changes: 3 additions & 5 deletions packages/x-data-grid-pro/src/components/GridPinnedRows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { getDataGridUtilityClass, gridClasses, useGridSelector } from '@mui/x-da
import {
GridPinnedRowsProps,
gridPinnedRowsSelector,
gridRenderContextSelector,
useGridPrivateApiContext,
} from '@mui/x-data-grid/internals';

Expand All @@ -20,18 +19,17 @@ export function GridPinnedRows({ position, virtualScroller }: GridPinnedRowsProp
const classes = useUtilityClasses();
const apiRef = useGridPrivateApiContext();

const renderContext = useGridSelector(apiRef, gridRenderContextSelector);
const pinnedRowsData = useGridSelector(apiRef, gridPinnedRowsSelector);
const rows = pinnedRowsData[position];

const pinnedRenderContext = React.useMemo(
() => ({
firstRowIndex: 0,
lastRowIndex: rows.length,
firstColumnIndex: renderContext.firstColumnIndex,
lastColumnIndex: renderContext.lastColumnIndex,
firstColumnIndex: -1,
lastColumnIndex: -1,
}),
[rows, renderContext.firstColumnIndex, renderContext.lastColumnIndex],
[rows],
);

if (rows.length === 0) {
Expand Down
Loading

0 comments on commit ad55b60

Please sign in to comment.