Skip to content

Commit

Permalink
[DataGrid] Extract getRowId API method as a selector (#16574)
Browse files Browse the repository at this point in the history
  • Loading branch information
MBilalShafi authored Feb 18, 2025
1 parent c505f40 commit 91d461d
Show file tree
Hide file tree
Showing 31 changed files with 133 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"GridRowHeightReturnValue": "The row height value. If <code>null</code> or <code>undefined</code> then the default row height is applied. If &quot;auto&quot; then the row height is calculated based on the content."
}
},
"getRowId": { "description": "Return the id of a given GridRowModel." },
"getRowId": {
"description": "Return the id of a given GridRowModel. Ensure the reference of this prop is stable to avoid performance implications. It could be done by either defining the prop outside of the component or by memoizing it."
},
"getRowSpacing": {
"description": "Function that allows to specify the spacing between rows.",
"typeDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@
"GridRowHeightReturnValue": "The row height value. If <code>null</code> or <code>undefined</code> then the default row height is applied. If &quot;auto&quot; then the row height is calculated based on the content."
}
},
"getRowId": { "description": "Return the id of a given GridRowModel." },
"getRowId": {
"description": "Return the id of a given GridRowModel. Ensure the reference of this prop is stable to avoid performance implications. It could be done by either defining the prop outside of the component or by memoizing it."
},
"getRowSpacing": {
"description": "Function that allows to specify the spacing between rows.",
"typeDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@
"GridRowHeightReturnValue": "The row height value. If <code>null</code> or <code>undefined</code> then the default row height is applied. If &quot;auto&quot; then the row height is calculated based on the content."
}
},
"getRowId": { "description": "Return the id of a given GridRowModel." },
"getRowId": {
"description": "Return the id of a given GridRowModel. Ensure the reference of this prop is stable to avoid performance implications. It could be done by either defining the prop outside of the component or by memoizing it."
},
"getRowSpacing": {
"description": "Function that allows to specify the spacing between rows.",
"typeDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ DataGridPremiumRaw.propTypes = {
getRowHeight: PropTypes.func,
/**
* Return the id of a given [[GridRowModel]].
* Ensure the reference of this prop is stable to avoid performance implications.
* It could be done by either defining the prop outside of the component or by memoizing it.
*/
getRowId: PropTypes.func,
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import {
rowSpanningStateInitializer,
useGridListView,
listViewStateInitializer,
propsStateInitializer,
} from '@mui/x-data-grid-pro/internals';
import { GridApiPremium, GridPrivateApiPremium } from '../models/gridApiPremium';
import { DataGridPremiumProcessedProps } from '../models/dataGridPremiumProps';
Expand Down Expand Up @@ -121,6 +122,7 @@ export const useDataGridPremiumComponent = (
/**
* Register all state initializers here.
*/
useGridInitializeState(propsStateInitializer, apiRef, props);
useGridInitializeState(headerFilteringStateInitializer, apiRef, props);
useGridInitializeState(rowGroupingStateInitializer, apiRef, props);
useGridInitializeState(aggregationStateInitializer, apiRef, props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const getAggregationCellValue = ({
// A.B
// A.B.A
// A.B.B
const rowNode = apiRef.current.getRowNode(rowId)!;
if (rowNode.type === 'group') {
const rowNode = apiRef.current.getRowNode(rowId);
if (rowNode?.type === 'group') {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import * as React from 'react';
import { RefObject } from '@mui/x-internals/types';
import { GridColDef, GridFilterOperator, GridRowId } from '@mui/x-data-grid-pro';
import { GridBaseColDef } from '@mui/x-data-grid-pro/internals';
import { GridApiPremium } from '../../../models/gridApiPremium';
import {
GridColDef,
GridFilterOperator,
GridRowId,
gridRowIdSelector,
gridRowTreeSelector,
} from '@mui/x-data-grid-pro';
import { type GridBaseColDef } from '@mui/x-data-grid-pro/internals';
import { GridApiPremium } from '../../../models/gridApiPremium';
import type {
GridAggregationCellMeta,
GridAggregationLookup,
GridAggregationPosition,
Expand Down Expand Up @@ -47,7 +53,7 @@ const getAggregationValueWrappedValueGetter: ColumnPropertyWrapper<'valueGetter'
getCellAggregationResult,
}) => {
const wrappedValueGetter: GridBaseColDef['valueGetter'] = (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId?.(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
const cellAggregationResult = rowId ? getCellAggregationResult(rowId, column.field) : null;
if (cellAggregationResult != null) {
return cellAggregationResult?.value ?? null;
Expand Down Expand Up @@ -75,7 +81,7 @@ const getAggregationValueWrappedValueFormatter: ColumnPropertyWrapper<'valueForm
}

const wrappedValueFormatter: GridBaseColDef['valueFormatter'] = (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
if (rowId != null) {
const cellAggregationResult = getCellAggregationResult(rowId, column.field);
if (cellAggregationResult != null) {
Expand Down Expand Up @@ -147,7 +153,8 @@ const getWrappedFilterOperators: ColumnPropertyWrapper<'filterOperators'> = ({
return null;
}
return (value, row, column, api) => {
if (getCellAggregationResult(apiRef.current.getRowId(row), column.field) != null) {
const rowId = gridRowIdSelector(apiRef.current.state, row);
if (getCellAggregationResult(rowId, column.field) != null) {
return true;
}
return filterFn(value, row, column, api);
Expand Down Expand Up @@ -197,7 +204,7 @@ export const wrapColumnWithAggregationValue = ({
field: string,
): GridAggregationLookup[GridRowId][string] | null => {
let cellAggregationPosition: GridAggregationPosition | null = null;
const rowNode = apiRef.current.getRowNode(id)!;
const rowNode = gridRowTreeSelector(apiRef)[id];

if (rowNode.type === 'group') {
cellAggregationPosition = 'inline';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
GridGroupNode,
GridTreeNodeWithRender,
GridValueFormatter,
gridRowIdSelector,
gridRowTreeSelector,
} from '@mui/x-data-grid-pro';
import { GridColumnRawLookup, isSingleSelectColDef } from '@mui/x-data-grid-pro/internals';
import { GridApiPremium } from '../../../models/gridApiPremium';
Expand Down Expand Up @@ -213,8 +215,8 @@ export const createGroupingColDefForOneGroupingCriteria = ({
return '';
},
valueGetter: (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId(row);
const rowNode = apiRef.current.getRowNode<GridTreeNodeWithRender>(rowId);
const rowId = gridRowIdSelector(apiRef.current.state, row);
const rowNode = gridRowTreeSelector(apiRef)[rowId] as GridTreeNodeWithRender;
if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow') {
return undefined;
}
Expand Down Expand Up @@ -343,8 +345,8 @@ export const createGroupingColDefForAllGroupingCriteria = ({
);
},
valueGetter: (value, row) => {
const rowId = apiRef.current.getRowId(row);
const rowNode = apiRef.current.getRowNode<GridTreeNodeWithRender>(rowId);
const rowId = gridRowIdSelector(apiRef.current.state, row);
const rowNode = gridRowTreeSelector(apiRef)[rowId] as GridTreeNodeWithRender;
if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow') {
return undefined;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ DataGridProRaw.propTypes = {
getRowHeight: PropTypes.func,
/**
* Return the id of a given [[GridRowModel]].
* Ensure the reference of this prop is stable to avoid performance implications.
* It could be done by either defining the prop outside of the component or by memoizing it.
*/
getRowId: PropTypes.func,
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
rowSpanningStateInitializer,
useGridListView,
listViewStateInitializer,
propsStateInitializer,
} from '@mui/x-data-grid/internals';
import { GridApiPro, GridPrivateApiPro } from '../models/gridApiPro';
import { DataGridProProcessedProps } from '../models/dataGridProProps';
Expand Down Expand Up @@ -111,6 +112,7 @@ export const useDataGridProComponent = (
/**
* Register all state initializers here.
*/
useGridInitializeState(propsStateInitializer, apiRef, props);
useGridInitializeState(headerFilteringStateInitializer, apiRef, props);
useGridInitializeState(rowSelectionStateInitializer, apiRef, props);
useGridInitializeState(detailPanelStateInitializer, apiRef, props);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { GRID_STRING_COL_DEF, GridColDef } from '@mui/x-data-grid';
import { GRID_STRING_COL_DEF, GridColDef, gridRowIdSelector } from '@mui/x-data-grid';
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from '@mui/x-data-grid/internals';
import { GridApiPro } from '../../../models/gridApiPro';
import { GridDetailPanelToggleCell } from '../../../components/GridDetailPanelToggleCell';
Expand All @@ -23,7 +23,7 @@ export const GRID_DETAIL_PANEL_TOGGLE_COL_DEF: GridColDef = {
align: 'left',
width: 40,
valueGetter: (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
const expandedRowIds = gridDetailPanelExpandedRowIdsSelector(
(apiRef.current as GridApiPro).state,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { GRID_STRING_COL_DEF, GridColDef } from '@mui/x-data-grid';
import {
GRID_STRING_COL_DEF,
GridColDef,
gridRowIdSelector,
gridRowTreeSelector,
} from '@mui/x-data-grid';
import { GRID_TREE_DATA_GROUPING_FIELD } from '@mui/x-data-grid/internals';

/**
Expand All @@ -14,8 +19,8 @@ export const GRID_TREE_DATA_GROUPING_COL_DEF: Omit<GridColDef, 'field' | 'editab
align: 'left',
width: 200,
valueGetter: (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId(row);
const rowNode = apiRef.current.getRowNode(rowId);
const rowId = gridRowIdSelector(apiRef.current.state, row);
const rowNode = gridRowTreeSelector(apiRef)[rowId];
return rowNode?.type === 'group' || rowNode?.type === 'leaf' ? rowNode.groupingKey : undefined;
},
};
Expand Down
2 changes: 2 additions & 0 deletions packages/x-data-grid/src/DataGrid/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ DataGridRaw.propTypes = {
getRowHeight: PropTypes.func,
/**
* Return the id of a given [[GridRowModel]].
* Ensure the reference of this prop is stable to avoid performance implications.
* It could be done by either defining the prop outside of the component or by memoizing it.
*/
getRowId: PropTypes.func,
/**
Expand Down
2 changes: 2 additions & 0 deletions packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
listViewStateInitializer,
useGridListView,
} from '../hooks/features/listView/useGridListView';
import { propsStateInitializer } from '../hooks/core/useGridProps';

export const useDataGridComponent = (
inputApiRef: RefObject<GridApiCommunity> | undefined,
Expand All @@ -81,6 +82,7 @@ export const useDataGridComponent = (
/**
* Register all state initializers here.
*/
useGridInitializeState(propsStateInitializer, apiRef, props);
useGridInitializeState(rowSelectionStateInitializer, apiRef, props);
useGridInitializeState(columnsStateInitializer, apiRef, props);
useGridInitializeState(rowsStateInitializer, apiRef, props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GridHeaderCheckbox } from '../components/columnSelection/GridHeaderChec
import { selectedIdsLookupSelector } from '../hooks/features/rowSelection/gridRowSelectionSelector';
import { GridColDef } from '../models/colDef/gridColDef';
import { GRID_BOOLEAN_COL_DEF } from './gridBooleanColDef';
import { gridRowIdSelector } from '../hooks/core/gridPropsSelectors';

export const GRID_CHECKBOX_SELECTION_FIELD = '__check__';

Expand All @@ -24,7 +25,7 @@ export const GRID_CHECKBOX_SELECTION_COL_DEF: GridColDef = {
display: 'flex',
valueGetter: (value, row, column, apiRef) => {
const selectionLookup = selectedIdsLookupSelector(apiRef);
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
return selectionLookup[rowId] !== undefined;
},
renderHeader: (params) => <GridHeaderCheckbox {...params} />,
Expand Down
5 changes: 3 additions & 2 deletions packages/x-data-grid/src/colDef/gridDateColDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getGridDateOperators } from './gridDateOperators';
import { GRID_STRING_COL_DEF } from './gridStringColDef';
import { GridColTypeDef, GridValueFormatter } from '../models/colDef/gridColDef';
import { renderEditDateCell } from '../components/cell/GridEditDateCell';
import { gridRowIdSelector } from '../hooks/core/gridPropsSelectors';

function throwIfNotDateObject({
value,
Expand Down Expand Up @@ -30,7 +31,7 @@ export const gridDateFormatter: GridValueFormatter = (value: Date, row, column,
if (!value) {
return '';
}
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
throwIfNotDateObject({ value, columnType: 'date', rowId, field: column.field });
return value.toLocaleDateString();
};
Expand All @@ -44,7 +45,7 @@ export const gridDateTimeFormatter: GridValueFormatter = (
if (!value) {
return '';
}
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);
throwIfNotDateObject({ value, columnType: 'dateTime', rowId, field: column.field });
return value.toLocaleString();
};
Expand Down
4 changes: 2 additions & 2 deletions packages/x-data-grid/src/colDef/gridSingleSelectColDef.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
isSingleSelectColDef,
} from '../components/panel/filterPanel/filterPanelUtils';
import { isObject } from '../utils/utils';
import { gridRowIdSelector } from '../hooks/core/gridPropsSelectors';

const isArrayOfObjects = (options: any): options is Array<Record<string, any>> => {
return typeof options[0] === 'object';
Expand All @@ -26,8 +27,7 @@ export const GRID_SINGLE_SELECT_COL_DEF: Omit<GridSingleSelectColDef, 'field'> =
getOptionLabel: defaultGetOptionLabel,
getOptionValue: defaultGetOptionValue,
valueFormatter(value, row, colDef, apiRef) {
// const { id, field, value, api } = params;
const rowId = apiRef.current.getRowId(row);
const rowId = gridRowIdSelector(apiRef.current.state, row);

if (!isSingleSelectColDef(colDef)) {
return '';
Expand Down
19 changes: 19 additions & 0 deletions packages/x-data-grid/src/hooks/core/gridPropsSelectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { GridStateCommunity } from '../../models/gridStateCommunity';
import type { GridRowId, GridRowModel } from '../../models/gridRows';
import { GRID_ID_AUTOGENERATED } from '../features/rows/gridRowsUtils';

/**
* Get the row id for a given row
* @param state - The grid state
* @param {GridRowModel} row - The row to get the id for
* @returns {GridRowId} The row id
*/
export const gridRowIdSelector = <State extends GridStateCommunity>(
state: State,
row: GridRowModel,
): GridRowId => {
if (GRID_ID_AUTOGENERATED in row) {
return row[GRID_ID_AUTOGENERATED];
}
return state.props.getRowId ? state.props.getRowId(row) : row.id;
};
1 change: 1 addition & 0 deletions packages/x-data-grid/src/hooks/core/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export type { GridPipeProcessingLookup } from './pipeProcessing';
export { gridRowIdSelector } from './gridPropsSelectors';
2 changes: 2 additions & 0 deletions packages/x-data-grid/src/hooks/core/useGridInitialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useGridLocaleText } from './useGridLocaleText';
import { useGridPipeProcessing } from './pipeProcessing';
import { useGridStrategyProcessing } from './strategyProcessing';
import { useGridStateInitialization } from './useGridStateInitialization';
import { useGridProps } from './useGridProps';

/**
* Initialize the technical pieces of the DataGrid (logger, state, ...) that any DataGrid implementation needs
Expand All @@ -23,6 +24,7 @@ export const useGridInitialization = <
const privateApiRef = useGridApiInitialization<PrivateApi, Api>(inputApiRef, props);

useGridRefs(privateApiRef);
useGridProps(privateApiRef, props);
useGridIsRtl(privateApiRef);
useGridLoggerFactory(privateApiRef, props);
useGridStateInitialization(privateApiRef);
Expand Down
30 changes: 30 additions & 0 deletions packages/x-data-grid/src/hooks/core/useGridProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';
import type { RefObject } from '@mui/x-internals/types';
import type { DataGridProps } from '../../models/props/DataGridProps';
import type { GridPrivateApiCommon } from '../../models/api/gridApiCommon';
import type { GridStateInitializer } from '../utils/useGridInitializeState';

type Props = Pick<DataGridProps, 'getRowId'>;

export const propsStateInitializer: GridStateInitializer<Props> = (state, props) => {
return {
...state,
props: {
getRowId: props.getRowId,
},
};
};

export const useGridProps = <PrivateApi extends GridPrivateApiCommon>(
apiRef: RefObject<PrivateApi>,
props: Props,
) => {
React.useEffect(() => {
apiRef.current.setState((state) => ({
...state,
props: {
getRowId: props.getRowId,
},
}));
}, [apiRef, props.getRowId]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const useGridRowSelection = (
return false;
}

const rowNode = apiRef.current.getRowNode(id);
const rowNode = gridRowTreeSelector(apiRef)[id];
if (rowNode?.type === 'footer' || rowNode?.type === 'pinnedRow') {
return false;
}
Expand Down Expand Up @@ -574,7 +574,7 @@ export const useGridRowSelection = (
}
}

const rowNode = apiRef.current.getRowNode(params.id);
const rowNode = gridRowTreeSelector(apiRef)[params.id];
if (rowNode!.type === 'pinnedRow') {
return;
}
Expand Down
Loading

0 comments on commit 91d461d

Please sign in to comment.