From 78cb39988e7550ebb1033a4ae1fddce82e449efb Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii Date: Tue, 15 Oct 2024 23:39:56 +0200 Subject: [PATCH] [DataGridPro] Fix scrolling performance when `rowHeight={undefined}` (#14983) --- packages/x-data-grid/src/DataGrid/index.ts | 1 - .../src/DataGrid/useDataGridProps.ts | 63 +------------------ .../constants/dataGridPropsDefaultValues.ts | 62 ++++++++++++++++++ .../features/dimensions/useGridDimensions.ts | 18 +++++- .../src/hooks/features/rows/gridRowsUtils.ts | 27 ++++++++ .../hooks/features/rows/useGridRowsMeta.ts | 37 ++--------- packages/x-data-grid/src/index.ts | 1 + 7 files changed, 113 insertions(+), 96 deletions(-) create mode 100644 packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts diff --git a/packages/x-data-grid/src/DataGrid/index.ts b/packages/x-data-grid/src/DataGrid/index.ts index 3f008be74fc8..8bbb546cef5e 100644 --- a/packages/x-data-grid/src/DataGrid/index.ts +++ b/packages/x-data-grid/src/DataGrid/index.ts @@ -1,2 +1 @@ export * from './DataGrid'; -export { DATA_GRID_PROPS_DEFAULT_VALUES } from './useDataGridProps'; diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index 124df2ee7140..1ae57fbf5d8f 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -8,8 +8,9 @@ import { } from '../models/props/DataGridProps'; import { GRID_DEFAULT_LOCALE_TEXT } from '../constants'; import { DATA_GRID_DEFAULT_SLOTS_COMPONENTS } from '../constants/defaultGridSlotsComponents'; -import { GridEditModes, GridSlotsComponent, GridValidRowModel } from '../models'; +import { GridSlotsComponent, GridValidRowModel } from '../models'; import { computeSlots, useProps } from '../internals/utils'; +import { DATA_GRID_PROPS_DEFAULT_VALUES } from '../constants/dataGridPropsDefaultValues'; const DATA_GRID_FORCED_PROPS: { [key in DataGridForcedPropsKey]?: DataGridProcessedProps[key] } = { disableMultipleColumnsFiltering: true, @@ -23,66 +24,6 @@ const DATA_GRID_FORCED_PROPS: { [key in DataGridForcedPropsKey]?: DataGridProces signature: 'DataGrid', }; -/** - * The default values of `DataGridPropsWithDefaultValues` to inject in the props of DataGrid. - */ -export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { - autoHeight: false, - autoPageSize: false, - autosizeOnMount: false, - checkboxSelection: false, - checkboxSelectionVisibleOnly: false, - clipboardCopyCellDelimiter: '\t', - columnBufferPx: 150, - columnHeaderHeight: 56, - disableAutosize: false, - disableColumnFilter: false, - disableColumnMenu: false, - disableColumnReorder: false, - disableColumnResize: false, - disableColumnSelector: false, - disableColumnSorting: false, - disableDensitySelector: false, - disableEval: false, - disableMultipleColumnsFiltering: false, - disableMultipleColumnsSorting: false, - disableMultipleRowSelection: false, - disableRowSelectionOnClick: false, - disableVirtualization: false, - editMode: GridEditModes.Cell, - filterDebounceMs: 150, - filterMode: 'client', - hideFooter: false, - hideFooterPagination: false, - hideFooterRowCount: false, - hideFooterSelectedRowCount: false, - ignoreDiacritics: false, - ignoreValueFormatterDuringExport: false, - // TODO v8: Update to 'select' - indeterminateCheckboxAction: 'deselect', - keepColumnPositionIfDraggedOutside: false, - keepNonExistentRowsSelected: false, - loading: false, - logger: console, - logLevel: process.env.NODE_ENV === 'production' ? ('error' as const) : ('warn' as const), - pageSizeOptions: [25, 50, 100], - pagination: false, - paginationMode: 'client', - resizeThrottleMs: 60, - rowBufferPx: 150, - rowHeight: 52, - rowPositionsDebounceMs: 166, - rows: [], - rowSelection: true, - rowSpacingType: 'margin', - showCellVerticalBorder: false, - showColumnVerticalBorder: false, - sortingMode: 'client', - sortingOrder: ['asc' as const, 'desc' as const, null], - throttleRowsMs: 0, - unstable_rowSpanning: false, -}; - const defaultSlots = DATA_GRID_DEFAULT_SLOTS_COMPONENTS; export const useDataGridProps = (inProps: DataGridProps) => { diff --git a/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts b/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts new file mode 100644 index 000000000000..689aa164e7a0 --- /dev/null +++ b/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts @@ -0,0 +1,62 @@ +import { GridEditModes } from '../models/gridEditRowModel'; +import type { DataGridPropsWithDefaultValues } from '../models/props/DataGridProps'; + +/** + * The default values of `DataGridPropsWithDefaultValues` to inject in the props of DataGrid. + */ +export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { + autoHeight: false, + autoPageSize: false, + autosizeOnMount: false, + checkboxSelection: false, + checkboxSelectionVisibleOnly: false, + clipboardCopyCellDelimiter: '\t', + columnBufferPx: 150, + columnHeaderHeight: 56, + disableAutosize: false, + disableColumnFilter: false, + disableColumnMenu: false, + disableColumnReorder: false, + disableColumnResize: false, + disableColumnSelector: false, + disableColumnSorting: false, + disableDensitySelector: false, + disableEval: false, + disableMultipleColumnsFiltering: false, + disableMultipleColumnsSorting: false, + disableMultipleRowSelection: false, + disableRowSelectionOnClick: false, + disableVirtualization: false, + editMode: GridEditModes.Cell, + filterDebounceMs: 150, + filterMode: 'client', + hideFooter: false, + hideFooterPagination: false, + hideFooterRowCount: false, + hideFooterSelectedRowCount: false, + ignoreDiacritics: false, + ignoreValueFormatterDuringExport: false, + // TODO v8: Update to 'select' + indeterminateCheckboxAction: 'deselect', + keepColumnPositionIfDraggedOutside: false, + keepNonExistentRowsSelected: false, + loading: false, + logger: console, + logLevel: process.env.NODE_ENV === 'production' ? ('error' as const) : ('warn' as const), + pageSizeOptions: [25, 50, 100], + pagination: false, + paginationMode: 'client', + resizeThrottleMs: 60, + rowBufferPx: 150, + rowHeight: 52, + rowPositionsDebounceMs: 166, + rows: [], + rowSelection: true, + rowSpacingType: 'margin', + showCellVerticalBorder: false, + showColumnVerticalBorder: false, + sortingMode: 'client', + sortingOrder: ['asc' as const, 'desc' as const, null], + throttleRowsMs: 0, + unstable_rowSpanning: false, +}; diff --git a/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts b/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts index 35fd29033f8d..d7c7971b99e8 100644 --- a/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts +++ b/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts @@ -27,9 +27,14 @@ import { gridRenderContextSelector } from '../virtualization'; import { useGridSelector } from '../../utils'; import { getVisibleRows } from '../../utils/useGridVisibleRows'; import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector'; -import { calculatePinnedRowsHeight } from '../rows/gridRowsUtils'; +import { + calculatePinnedRowsHeight, + getValidRowHeight, + rowHeightWarning, +} from '../rows/gridRowsUtils'; import { getTotalHeaderHeight } from '../columns/gridColumnsUtils'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; +import { DATA_GRID_PROPS_DEFAULT_VALUES } from '../../../constants/dataGridPropsDefaultValues'; type RootProps = Pick< DataGridProcessedProps, @@ -92,7 +97,16 @@ export function useGridDimensions( const rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector); const pinnedColumns = useGridSelector(apiRef, gridVisiblePinnedColumnDefinitionsSelector); const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector); - const rowHeight = Math.floor(props.rowHeight * densityFactor); + const validRowHeight = React.useMemo( + () => + getValidRowHeight( + props.rowHeight, + DATA_GRID_PROPS_DEFAULT_VALUES.rowHeight, + rowHeightWarning, + ), + [props.rowHeight], + ); + const rowHeight = Math.floor(validRowHeight * densityFactor); const headerHeight = Math.floor(props.columnHeaderHeight * densityFactor); const groupHeaderHeight = Math.floor( (props.columnGroupHeaderHeight ?? props.columnHeaderHeight) * densityFactor, diff --git a/packages/x-data-grid/src/hooks/features/rows/gridRowsUtils.ts b/packages/x-data-grid/src/hooks/features/rows/gridRowsUtils.ts index 53d022c86853..e7b217aaa9a3 100644 --- a/packages/x-data-grid/src/hooks/features/rows/gridRowsUtils.ts +++ b/packages/x-data-grid/src/hooks/features/rows/gridRowsUtils.ts @@ -437,3 +437,30 @@ export function computeRowsUpdates( }); return nonPinnedRowsUpdates; } + +let warnedOnceInvalidRowHeight = false; + +export const getValidRowHeight = ( + rowHeightProp: any, + defaultRowHeight: number, + warningMessage: string, +) => { + if (typeof rowHeightProp === 'number' && rowHeightProp > 0) { + return rowHeightProp; + } + if ( + process.env.NODE_ENV !== 'production' && + !warnedOnceInvalidRowHeight && + typeof rowHeightProp !== 'undefined' && + rowHeightProp !== null + ) { + console.warn(warningMessage); + warnedOnceInvalidRowHeight = true; + } + return defaultRowHeight; +}; + +export const rowHeightWarning = [ + `MUI X: The \`rowHeight\` prop should be a number greater than 0.`, + `The default value will be used instead.`, +].join('\n'); diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts b/packages/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts index bc1bfcb48f18..bb49e04a9ae6 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts @@ -14,7 +14,8 @@ import { gridSortModelSelector } from '../sorting/gridSortingSelector'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { useGridRegisterPipeApplier } from '../../core/pipeProcessing'; import { gridPinnedRowsSelector } from './gridRowsSelector'; -import { DATA_GRID_PROPS_DEFAULT_VALUES } from '../../../DataGrid/useDataGridProps'; +import { gridDimensionsSelector } from '../dimensions/gridDimensionsSelectors'; +import { getValidRowHeight } from './gridRowsUtils'; // TODO: I think the row heights can now be encoded as a single `size` instead of `sizes.baseXxxx` @@ -26,32 +27,6 @@ export const rowsMetaStateInitializer: GridStateInitializer = (state) => ({ }, }); -let warnedOnceInvalidRowHeight = false; -const getValidRowHeight = ( - rowHeightProp: any, - defaultRowHeight: number, - warningMessage: string, -) => { - if (typeof rowHeightProp === 'number' && rowHeightProp > 0) { - return rowHeightProp; - } - if ( - process.env.NODE_ENV !== 'production' && - !warnedOnceInvalidRowHeight && - typeof rowHeightProp !== 'undefined' && - rowHeightProp !== null - ) { - console.warn(warningMessage); - warnedOnceInvalidRowHeight = true; - } - return defaultRowHeight; -}; - -const rowHeightWarning = [ - `MUI X: The \`rowHeight\` prop should be a number greater than 0.`, - `The default value will be used instead.`, -].join('\n'); - const getRowHeightWarning = [ `MUI X: The \`getRowHeight\` prop should return a number greater than 0 or 'auto'.`, `The default value will be used instead.`, @@ -93,12 +68,10 @@ export const useGridRowsMeta = ( const sortModel = useGridSelector(apiRef, gridSortModelSelector); const currentPage = useGridVisibleRows(apiRef, props); const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector); - const validRowHeight = getValidRowHeight( - props.rowHeight, - DATA_GRID_PROPS_DEFAULT_VALUES.rowHeight, - rowHeightWarning, + const rowHeight = useGridSelector( + apiRef, + () => gridDimensionsSelector(apiRef.current.state).rowHeight, ); - const rowHeight = Math.floor(validRowHeight * densityFactor); const hydrateRowsMeta = React.useCallback(() => { hasRowWithAutoHeight.current = false; diff --git a/packages/x-data-grid/src/index.ts b/packages/x-data-grid/src/index.ts index c503f1f99027..16f48bc18ec5 100644 --- a/packages/x-data-grid/src/index.ts +++ b/packages/x-data-grid/src/index.ts @@ -9,6 +9,7 @@ export * from './DataGrid'; export * from './components'; export * from './constants'; +export * from './constants/dataGridPropsDefaultValues'; export * from './hooks'; export * from './models'; export * from './context';