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 (mui#15648)

Co-authored-by: Andrew Cherniavskyi <[email protected]>
  • Loading branch information
cherniavskii committed Feb 5, 2025
1 parent 6f60283 commit eb74477
Show file tree
Hide file tree
Showing 57 changed files with 765 additions and 433 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
12 changes: 8 additions & 4 deletions docs/data/data-grid/filtering-recipes/FilteredRowCount.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ export default function FilteredRowCount() {

const getFilteredRowsCount = React.useCallback(
(filterModel) => {
const { filteredRowsLookup } = apiRef.current.getFilterState(filterModel);
return Object.keys(filteredRowsLookup).filter(
(rowId) => filteredRowsLookup[rowId] === true,
).length;
const rowIds = apiRef.current?.getAllRowIds();
const filterState = apiRef.current?.getFilterState(filterModel);
if (!rowIds || !filterState) {
return 0;
}

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

const getFilteredRowsCount = React.useCallback(
(filterModel: GridFilterModel) => {
const { filteredRowsLookup } = apiRef.current.getFilterState(filterModel);
return Object.keys(filteredRowsLookup).filter(
(rowId) => filteredRowsLookup[rowId] === true,
).length;
const rowIds = apiRef.current?.getAllRowIds();
const filterState = apiRef.current?.getFilterState(filterModel);
if (!rowIds || !filterState) {
return 0;
}

const { filteredRowsLookup } = filterState;
return rowIds.filter((rowId) => filteredRowsLookup[rowId] !== false).length;
},
[apiRef],
);
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 @@ -57,7 +59,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 @@ -121,7 +121,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 @@ -142,11 +141,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 @@ -64,7 +64,6 @@ export const useGridAggregation = (
const currentModel = gridAggregationModelSelector(apiRef);
if (currentModel !== model) {
apiRef.current.setState(mergeStateWithAggregationModel(model));
apiRef.current.forceUpdate();
}
},
[apiRef],
Expand Down Expand Up @@ -118,7 +117,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');
}
}, [apiRef, applyAggregation, props.aggregationFunctions, props.disableAggregation]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,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 @@ -9,7 +9,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 @@ -293,6 +289,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 @@ -332,7 +330,7 @@ export const useGridCellSelection = (
}

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

const handleCellMouseOver = React.useCallback<GridEventListener<'cellMouseOver'>>(
(params, event) => {
Expand All @@ -355,6 +353,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 @@ -379,7 +378,7 @@ export const useGridCellSelection = (
stopAutoScroll();
}
},
[apiRef, startAutoScroll, stopAutoScroll, totalHeaderHeight, dimensions],
[apiRef, startAutoScroll, stopAutoScroll, totalHeaderHeight],
);

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

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

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

const canUpdateFocus = React.useCallback<GridPipeProcessor<'canUpdateFocus'>>(
Expand Down Expand Up @@ -567,6 +568,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 @@ -595,7 +597,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 @@ -79,9 +78,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 @@ -141,7 +140,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 @@ -44,7 +46,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 @@ -111,7 +111,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 @@ -129,11 +128,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 eb74477

Please sign in to comment.