diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index e507c4f395bcd..7f8d91cb76877 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -169,7 +169,9 @@ "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" 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": { diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index d267b6ea85223..9cabc89c55721 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -150,7 +150,9 @@ "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" 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": { diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 569d3272a60c3..937d825405e11 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -118,7 +118,9 @@ "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" 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": { diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index e40d38077596a..57aabc9ced442 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -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, /** diff --git a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx index c6b97d749f209..b76f5f62925d8 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx @@ -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'; @@ -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); diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts index d7b633cb9c86f..f86d69c707b7a 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts @@ -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; } diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx b/packages/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx index 56ce6a431dd26..53df47f7e6717 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/wrapColumnWithAggregation.tsx @@ -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, @@ -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; @@ -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) { @@ -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); @@ -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'; diff --git a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx index 9328cdcf2ca0c..6882db40d8395 100644 --- a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -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'; @@ -213,8 +215,8 @@ export const createGroupingColDefForOneGroupingCriteria = ({ return ''; }, 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] as GridTreeNodeWithRender; if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow') { return undefined; } @@ -343,8 +345,8 @@ export const createGroupingColDefForAllGroupingCriteria = ({ ); }, valueGetter: (value, row) => { - const rowId = apiRef.current.getRowId(row); - const rowNode = apiRef.current.getRowNode(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; } diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index d40d64b331316..6dd071b421388 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -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, /** diff --git a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index 51040a83f2c5b..c09a70b8b200e 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -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'; @@ -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); diff --git a/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx b/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx index 16998e55615fb..3eeedf11b3f60 100644 --- a/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx @@ -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'; @@ -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, ); diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts b/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts index f9f27fdd5d744..c2d3229043ca5 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataGroupColDef.ts @@ -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'; /** @@ -14,8 +19,8 @@ export const GRID_TREE_DATA_GROUPING_COL_DEF: Omit { - 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; }, }; diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 6086f7cc88dd0..860a3f728ccf2 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -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, /** diff --git a/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx index 36bc1d286372d..f1ef3ea3dd88e 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -62,6 +62,7 @@ import { listViewStateInitializer, useGridListView, } from '../hooks/features/listView/useGridListView'; +import { propsStateInitializer } from '../hooks/core/useGridProps'; export const useDataGridComponent = ( inputApiRef: RefObject | undefined, @@ -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); diff --git a/packages/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx b/packages/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx index 85305b10a3e62..65a81f3953608 100644 --- a/packages/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx +++ b/packages/x-data-grid/src/colDef/gridCheckboxSelectionColDef.tsx @@ -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__'; @@ -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) => , diff --git a/packages/x-data-grid/src/colDef/gridDateColDef.ts b/packages/x-data-grid/src/colDef/gridDateColDef.ts index 314c31869f6f3..160deefbc4410 100644 --- a/packages/x-data-grid/src/colDef/gridDateColDef.ts +++ b/packages/x-data-grid/src/colDef/gridDateColDef.ts @@ -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, @@ -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(); }; @@ -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(); }; diff --git a/packages/x-data-grid/src/colDef/gridSingleSelectColDef.tsx b/packages/x-data-grid/src/colDef/gridSingleSelectColDef.tsx index 859e4f0a3525a..195f6702eaf44 100644 --- a/packages/x-data-grid/src/colDef/gridSingleSelectColDef.tsx +++ b/packages/x-data-grid/src/colDef/gridSingleSelectColDef.tsx @@ -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> => { return typeof options[0] === 'object'; @@ -26,8 +27,7 @@ export const GRID_SINGLE_SELECT_COL_DEF: Omit = 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 ''; diff --git a/packages/x-data-grid/src/hooks/core/gridPropsSelectors.ts b/packages/x-data-grid/src/hooks/core/gridPropsSelectors.ts new file mode 100644 index 0000000000000..15301960ca83f --- /dev/null +++ b/packages/x-data-grid/src/hooks/core/gridPropsSelectors.ts @@ -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: 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; +}; diff --git a/packages/x-data-grid/src/hooks/core/index.ts b/packages/x-data-grid/src/hooks/core/index.ts index 880078f896661..be2e20c455b6b 100644 --- a/packages/x-data-grid/src/hooks/core/index.ts +++ b/packages/x-data-grid/src/hooks/core/index.ts @@ -1 +1,2 @@ export type { GridPipeProcessingLookup } from './pipeProcessing'; +export { gridRowIdSelector } from './gridPropsSelectors'; diff --git a/packages/x-data-grid/src/hooks/core/useGridInitialization.ts b/packages/x-data-grid/src/hooks/core/useGridInitialization.ts index ba4026364b234..9a591759a9152 100644 --- a/packages/x-data-grid/src/hooks/core/useGridInitialization.ts +++ b/packages/x-data-grid/src/hooks/core/useGridInitialization.ts @@ -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 @@ -23,6 +24,7 @@ export const useGridInitialization = < const privateApiRef = useGridApiInitialization(inputApiRef, props); useGridRefs(privateApiRef); + useGridProps(privateApiRef, props); useGridIsRtl(privateApiRef); useGridLoggerFactory(privateApiRef, props); useGridStateInitialization(privateApiRef); diff --git a/packages/x-data-grid/src/hooks/core/useGridProps.ts b/packages/x-data-grid/src/hooks/core/useGridProps.ts new file mode 100644 index 0000000000000..33222d7d89234 --- /dev/null +++ b/packages/x-data-grid/src/hooks/core/useGridProps.ts @@ -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; + +export const propsStateInitializer: GridStateInitializer = (state, props) => { + return { + ...state, + props: { + getRowId: props.getRowId, + }, + }; +}; + +export const useGridProps = ( + apiRef: RefObject, + props: Props, +) => { + React.useEffect(() => { + apiRef.current.setState((state) => ({ + ...state, + props: { + getRowId: props.getRowId, + }, + })); + }, [apiRef, props.getRowId]); +}; diff --git a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts index 512f1c8538e45..25f95e32ff44d 100644 --- a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts +++ b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts @@ -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; } @@ -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; } diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts b/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts index 7d4f2af30835a..c2d367941f9e5 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts @@ -19,6 +19,7 @@ import { gridRowMaximumTreeDepthSelector, gridRowGroupsToFetchSelector, } from './gridRowsSelector'; +import { gridRowIdSelector } from '../../core/gridPropsSelectors'; import { useTimeout } from '../../utils/useTimeout'; import { GridSignature, useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; @@ -111,18 +112,9 @@ export const useGridRows = ( [apiRef], ); - const getRowIdProp = props.getRowId; const getRowId = React.useCallback( - (row) => { - if (GRID_ID_AUTOGENERATED in row) { - return row[GRID_ID_AUTOGENERATED]; - } - if (getRowIdProp) { - return getRowIdProp(row); - } - return row.id; - }, - [getRowIdProp], + (row) => gridRowIdSelector(apiRef.current.state, row), + [apiRef], ); const throttledRowsChange = React.useCallback( diff --git a/packages/x-data-grid/src/hooks/features/sorting/gridSortingUtils.ts b/packages/x-data-grid/src/hooks/features/sorting/gridSortingUtils.ts index 4614c29735037..18608a8821436 100644 --- a/packages/x-data-grid/src/hooks/features/sorting/gridSortingUtils.ts +++ b/packages/x-data-grid/src/hooks/features/sorting/gridSortingUtils.ts @@ -11,6 +11,7 @@ import { GridSortModel, GridSortCellParams, } from '../../../models/gridSortModel'; +import { gridRowTreeSelector } from '../rows/gridRowsSelector'; type GridSortingFieldComparator = { getSortCellParams: (id: GridRowId) => GridSortCellParams; @@ -82,7 +83,7 @@ const parseSortItem = ( const getSortCellParams = (id: GridRowId): GridSortCellParams => ({ id, field: column.field, - rowNode: apiRef.current.getRowNode(id)!, + rowNode: gridRowTreeSelector(apiRef)[id], value: apiRef.current.getCellValue(id, column.field), api: apiRef.current, }); diff --git a/packages/x-data-grid/src/internals/index.ts b/packages/x-data-grid/src/internals/index.ts index 9483a51936d5e..4d6703bd7bca7 100644 --- a/packages/x-data-grid/src/internals/index.ts +++ b/packages/x-data-grid/src/internals/index.ts @@ -12,6 +12,7 @@ export { GridHeaders } from '../components/GridHeaders'; export { GridBaseColumnHeaders } from '../components/columnHeaders/GridBaseColumnHeaders'; export { DATA_GRID_DEFAULT_SLOTS_COMPONENTS } from '../constants/defaultGridSlotsComponents'; +export { propsStateInitializer } from '../hooks/core/useGridProps'; export { getGridFilter } from '../components/panel/filterPanel/GridFilterPanel'; export { useGridRegisterPipeProcessor } from '../hooks/core/pipeProcessing'; export type { GridPipeProcessor } from '../hooks/core/pipeProcessing'; diff --git a/packages/x-data-grid/src/models/api/gridRowApi.ts b/packages/x-data-grid/src/models/api/gridRowApi.ts index b54617e856a4a..6e8f79356f885 100644 --- a/packages/x-data-grid/src/models/api/gridRowApi.ts +++ b/packages/x-data-grid/src/models/api/gridRowApi.ts @@ -77,7 +77,6 @@ export interface GridRowApi { getRowId: (row: R) => GridRowId; /** * Gets the row node from the internal tree structure. - * TODO rows v6: Rename `getTreeNode` * @param {GridRowId} id The id of the row. * @returns {GridTreeNode} The tree node. */ diff --git a/packages/x-data-grid/src/models/gridStateCommunity.ts b/packages/x-data-grid/src/models/gridStateCommunity.ts index 89e37b25b4505..3a7ee74e40f05 100644 --- a/packages/x-data-grid/src/models/gridStateCommunity.ts +++ b/packages/x-data-grid/src/models/gridStateCommunity.ts @@ -19,6 +19,7 @@ import type { GridTabIndexState, GridVirtualizationState, } from '../hooks'; +import type { DataGridProps } from './props/DataGridProps'; import type { GridRowsMetaState } from '../hooks/features/rows/gridRowsMetaState'; import type { GridEditingState } from './gridEditRowModel'; import { GridHeaderFilteringState } from './gridHeaderFilteringModel'; @@ -28,11 +29,18 @@ import type { GridColumnResizeState } from '../hooks/features/columnResize'; import type { GridRowSpanningState } from '../hooks/features/rows/useGridRowSpanning'; import type { GridListViewState } from '../hooks/features/listView/useGridListView'; +/** + * Some props are passed on the state to enable grid selectors to select + * and react to them. + */ +type GridStateProps = Pick; + /** * The state of Data Grid. */ export interface GridStateCommunity { isRtl: boolean; + props: GridStateProps; dimensions: GridDimensionsState; rows: GridRowsState; visibleRowsLookup: GridVisibleRowsLookupState; diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index ff8ac24293f7a..c98f82e768de1 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -784,6 +784,8 @@ export interface DataGridPropsWithoutDefaultValue[]; /** * 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?: GridRowIdGetter; /** diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index ece2071aa913b..443b6af3eabf9 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -519,6 +519,7 @@ { "name": "GridRowHeightReturnValue", "kind": "TypeAlias" }, { "name": "GridRowId", "kind": "TypeAlias" }, { "name": "GridRowIdGetter", "kind": "TypeAlias" }, + { "name": "gridRowIdSelector", "kind": "Variable" }, { "name": "GridRowIdToModelLookup", "kind": "TypeAlias" }, { "name": "gridRowMaximumTreeDepthSelector", "kind": "Variable" }, { "name": "GridRowMode", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 04ae940f10f23..9be2e06b9a056 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -472,6 +472,7 @@ { "name": "GridRowHeightReturnValue", "kind": "TypeAlias" }, { "name": "GridRowId", "kind": "TypeAlias" }, { "name": "GridRowIdGetter", "kind": "TypeAlias" }, + { "name": "gridRowIdSelector", "kind": "Variable" }, { "name": "GridRowIdToModelLookup", "kind": "TypeAlias" }, { "name": "gridRowMaximumTreeDepthSelector", "kind": "Variable" }, { "name": "GridRowMode", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index b68458c02d909..9ebc8d968658b 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -427,6 +427,7 @@ { "name": "GridRowHeightReturnValue", "kind": "TypeAlias" }, { "name": "GridRowId", "kind": "TypeAlias" }, { "name": "GridRowIdGetter", "kind": "TypeAlias" }, + { "name": "gridRowIdSelector", "kind": "Variable" }, { "name": "GridRowIdToModelLookup", "kind": "TypeAlias" }, { "name": "gridRowMaximumTreeDepthSelector", "kind": "Variable" }, { "name": "GridRowMode", "kind": "TypeAlias" },