diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js
index 58cdeef72eb40..06da1d5d56555 100644
--- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js
+++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.js
@@ -60,11 +60,14 @@ export default function ColumnAutosizingAsync() {
setIsLoading(true);
getFakeData(100)
.then((data) => {
- return ReactDOM.flushSync(() => {
+ ReactDOM.flushSync(() => {
setIsLoading(false);
apiRef.current.updateRows(data.rows);
});
})
+ // `sleep`/`setTimeout` is required because `.updateRows` is an
+ // async function throttled to avoid choking on frequent changes.
+ .then(() => sleep(0))
.then(() =>
apiRef.current.autosizeColumns({
includeHeaders: true,
@@ -103,3 +106,9 @@ export default function ColumnAutosizingAsync() {
);
}
+
+function sleep(ms) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+}
diff --git a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx
index 3c00a2b4bb01f..650f0e1bced9e 100644
--- a/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx
+++ b/docs/data/data-grid/column-dimensions/ColumnAutosizingAsync.tsx
@@ -60,11 +60,14 @@ export default function ColumnAutosizingAsync() {
setIsLoading(true);
getFakeData(100)
.then((data) => {
- return ReactDOM.flushSync(() => {
+ ReactDOM.flushSync(() => {
setIsLoading(false);
apiRef.current.updateRows(data.rows);
});
})
+ // `sleep`/`setTimeout` is required because `.updateRows` is an
+ // async function throttled to avoid choking on frequent changes.
+ .then(() => sleep(0))
.then(() =>
apiRef.current.autosizeColumns({
includeHeaders: true,
@@ -103,3 +106,9 @@ export default function ColumnAutosizingAsync() {
);
}
+
+function sleep(ms: number) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+}
diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.js b/docs/data/data-grid/demo/FullFeaturedDemo.js
index ef0717f61f405..3fc0fb9d27edc 100644
--- a/docs/data/data-grid/demo/FullFeaturedDemo.js
+++ b/docs/data/data-grid/demo/FullFeaturedDemo.js
@@ -301,7 +301,6 @@ export default function FullFeaturedDemo() {
loading={loading}
checkboxSelection
disableRowSelectionOnClick
- rowThreshold={0}
initialState={{
...data.initialState,
pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] },
diff --git a/docs/data/data-grid/demo/FullFeaturedDemo.tsx b/docs/data/data-grid/demo/FullFeaturedDemo.tsx
index bb11d75390382..2928393ef60ec 100644
--- a/docs/data/data-grid/demo/FullFeaturedDemo.tsx
+++ b/docs/data/data-grid/demo/FullFeaturedDemo.tsx
@@ -341,7 +341,6 @@ export default function FullFeaturedDemo() {
loading={loading}
checkboxSelection
disableRowSelectionOnClick
- rowThreshold={0}
initialState={{
...data.initialState,
pinnedColumns: { left: [GRID_CHECKBOX_SELECTION_FIELD, 'desk'] },
diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.js b/docs/data/data-grid/master-detail/BasicDetailPanels.js
index 20da411552c06..172e2c73444a1 100644
--- a/docs/data/data-grid/master-detail/BasicDetailPanels.js
+++ b/docs/data/data-grid/master-detail/BasicDetailPanels.js
@@ -175,7 +175,6 @@ export default function BasicDetailPanels() {
diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx
index b9c17508bd5b5..e34bdf9861969 100644
--- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx
+++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx
@@ -177,7 +177,6 @@ export default function BasicDetailPanels() {
diff --git a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview
index ea6bfcbf5f283..ac41382b6e510 100644
--- a/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview
+++ b/docs/data/data-grid/master-detail/BasicDetailPanels.tsx.preview
@@ -1,7 +1,6 @@
\ No newline at end of file
diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.js b/docs/data/data-grid/master-detail/ControlMasterDetail.js
index ac0e5159d101e..bebc52b7b1778 100644
--- a/docs/data/data-grid/master-detail/ControlMasterDetail.js
+++ b/docs/data/data-grid/master-detail/ControlMasterDetail.js
@@ -29,7 +29,6 @@ export default function ControlMasterDetail() {
(
{`Order #${row.id}`}
)}
diff --git a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx
index 77c09b13a4e4a..611e8f8dd434f 100644
--- a/docs/data/data-grid/master-detail/ControlMasterDetail.tsx
+++ b/docs/data/data-grid/master-detail/ControlMasterDetail.tsx
@@ -37,7 +37,6 @@ export default function ControlMasterDetail() {
(
{`Order #${row.id}`}
)}
diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js
index af60da408ca75..0f9a8b1b1f648 100644
--- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js
+++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.js
@@ -30,7 +30,6 @@ export default function CustomizeDetailPanelToggle() {
diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx
index 4692667b60d5f..47a78a7af50a3 100644
--- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx
+++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx
@@ -34,7 +34,6 @@ export default function CustomizeDetailPanelToggle() {
diff --git a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview
index 953b7b32aa504..d89161b50e8d3 100644
--- a/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview
+++ b/docs/data/data-grid/master-detail/CustomizeDetailPanelToggle.tsx.preview
@@ -1,7 +1,6 @@
\ No newline at end of file
diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js
index 6819a2be2b18b..cc6d34bac8231 100644
--- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js
+++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.js
@@ -228,7 +228,6 @@ export default function DetailPanelAutoHeight() {
diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx
index dfe9d815e169f..ed845bdc8f50c 100644
--- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx
+++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx
@@ -234,7 +234,6 @@ export default function DetailPanelAutoHeight() {
diff --git a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview
index ea6bfcbf5f283..ac41382b6e510 100644
--- a/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview
+++ b/docs/data/data-grid/master-detail/DetailPanelAutoHeight.tsx.preview
@@ -1,7 +1,6 @@
\ No newline at end of file
diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.js b/docs/data/data-grid/master-detail/FormDetailPanel.js
index ce6831835d533..a09c4b6ab2e21 100644
--- a/docs/data/data-grid/master-detail/FormDetailPanel.js
+++ b/docs/data/data-grid/master-detail/FormDetailPanel.js
@@ -131,7 +131,6 @@ export default function FormDetailPanel() {
diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx b/docs/data/data-grid/master-detail/FormDetailPanel.tsx
index f202ae9ba07e4..12d6f209fc9b7 100644
--- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx
+++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx
@@ -139,7 +139,6 @@ export default function FormDetailPanel() {
diff --git a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview
index ea6bfcbf5f283..ac41382b6e510 100644
--- a/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview
+++ b/docs/data/data-grid/master-detail/FormDetailPanel.tsx.preview
@@ -1,7 +1,6 @@
\ No newline at end of file
diff --git a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js
index 16bd2837aba38..c7aed919254cf 100644
--- a/docs/data/data-grid/master-detail/FullWidthDetailPanel.js
+++ b/docs/data/data-grid/master-detail/FullWidthDetailPanel.js
@@ -201,7 +201,6 @@ export default function FullWidthDetailPanel() {
{ ... }, []);
```
-Depending on the height of the detail panel, you may see a blank space when scrolling.
-This is caused by the data grid using a lazy approach to update the rendered rows.
-Set `rowThreshold` to 0 to force new rows to be rendered more often to fill the blank space.
-Note that this may reduce the performance.
-
-```tsx
-
-```
-
:::
## Infer height from the content
diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js
index b789fd690dc4c..014b0e55bfec3 100644
--- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js
+++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.js
@@ -39,7 +39,7 @@ export default function ColumnVirtualizationGrid() {
return (
-
+
);
}
diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx
index ef0aa8f4d8a9f..c314fa3160c4e 100644
--- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx
+++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx
@@ -49,7 +49,7 @@ export default function ColumnVirtualizationGrid() {
return (
-
+
);
}
diff --git a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview
index 0fa5d537a93f7..ce7543c27f818 100644
--- a/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview
+++ b/docs/data/data-grid/virtualization/ColumnVirtualizationGrid.tsx.preview
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/data/data-grid/virtualization/virtualization.md b/docs/data/data-grid/virtualization/virtualization.md
index 201affbcfc9ff..bc14f817113f9 100644
--- a/docs/data/data-grid/virtualization/virtualization.md
+++ b/docs/data/data-grid/virtualization/virtualization.md
@@ -11,7 +11,7 @@ _\*unlimited: Browsers set a limit on the number of pixels a scroll container ca
Row virtualization is the insertion and removal of rows as the data grid scrolls vertically.
-The grid renders twice as many rows as are visible. It isn't configurable yet.
+The grid renders some additional rows above and below the visible rows. You can use `rowBufferPx` prop to hint to the Data Grid the area to render, but this value may not be respected in certain situations, for example during high-speed scrolling.
Row virtualization is limited to 100 rows in the `DataGrid` component.
## Column virtualization
@@ -23,11 +23,11 @@ Column virtualization is the insertion and removal of columns as the data grid s
- Overscanning more allows the built-in search feature of the browser to find more matching cells.
- Overscanning too much can negatively impact performance.
-By default, 2 columns are rendered outside of the viewport. You can change this option with the `columnBuffer` prop. The following demo renders 1,000 columns in total:
+By default, columns coming under 150 pixels region are rendered outside of the viewport. You can change this option with the `columnBufferPx` prop. As for `rowBufferPx`, the value may be ignored in some situations. The following demo renders 1,000 columns in total:
{{"demo": "ColumnVirtualizationGrid.js", "bg": "inline"}}
-You can disable column virtualization by setting the column buffer to a higher number than the number of rendered columns, for example with `columnBuffer={columns.length}` or `columnBuffer={Number.MAX_SAFE_INTEGER}`.
+You can disable column virtualization by calling `apiRef.current.unstable_setColumnVirtualization(false)`, or by setting the column buffer to the number of total columns.
## Disable virtualization
diff --git a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md
index 0c939947a016d..c3fc8fc79c1c7 100644
--- a/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md
+++ b/docs/data/migration/migration-data-grid-v6/migration-data-grid-v6.md
@@ -114,9 +114,10 @@ As a result, the following changes have been made:
- Pinned row and column sections are now contained in the virtual scroller.
- The cell inner wrapper `.MuiDataGrid-cellContent` has been removed.
-
+- The props `rowBuffer` and `columnBuffer` were renamed to `rowBufferPx` and `columnBufferPx`.
+ Their value is now a pixel value rather than a number of items. Their default value is now `150`.
### Removed props
@@ -143,6 +144,8 @@ As a result, the following changes have been made:
};
```
+- The props `rowThreshold` and `columnThreshold` have been removed.
+ If you had the `rowThreshold` prop set to `0` to force new rows to be rendered more often – this is no longer necessary.
- ✅ Some feature flags were removed from the `experimentalFeatures` prop. These features are now stable and enabled by default:
- [`columnGrouping`](/x/react-data-grid/column-groups/)
- [`clipboardPaste`](/x/react-data-grid/clipboard/#clipboard-paste)
diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json
index 4c43103ed7e0b..25c4610c05ebc 100644
--- a/docs/pages/x/api/data-grid/data-grid-premium.json
+++ b/docs/pages/x/api/data-grid/data-grid-premium.json
@@ -36,9 +36,8 @@
"checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" },
"classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } },
"clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" },
- "columnBuffer": { "type": { "name": "number" }, "default": "3" },
+ "columnBufferPx": { "type": { "name": "number" }, "default": "150" },
"columnHeaderHeight": { "type": { "name": "number" }, "default": "56" },
- "columnThreshold": { "type": { "name": "number" }, "default": "3" },
"columnVisibilityModel": { "type": { "name": "object" } },
"defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" },
"density": {
@@ -553,7 +552,7 @@
"returned": "Promise | R"
}
},
- "rowBuffer": { "type": { "name": "number" }, "default": "3" },
+ "rowBufferPx": { "type": { "name": "number" }, "default": "150" },
"rowCount": { "type": { "name": "number" } },
"rowGroupingColumnMode": {
"type": { "name": "enum", "description": "'multiple'
| 'single'" },
@@ -578,7 +577,6 @@
"type": { "name": "enum", "description": "'border'
| 'margin'" },
"default": "\"margin\""
},
- "rowThreshold": { "type": { "name": "number" }, "default": "3" },
"scrollbarSize": { "type": { "name": "number" } },
"scrollEndThreshold": { "type": { "name": "number" }, "default": "80" },
"showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" },
diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json
index 6c2382cfa2982..7b50ed4ccad70 100644
--- a/docs/pages/x/api/data-grid/data-grid-pro.json
+++ b/docs/pages/x/api/data-grid/data-grid-pro.json
@@ -25,9 +25,8 @@
"checkboxSelectionVisibleOnly": { "type": { "name": "bool" }, "default": "false" },
"classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } },
"clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" },
- "columnBuffer": { "type": { "name": "number" }, "default": "3" },
+ "columnBufferPx": { "type": { "name": "number" }, "default": "150" },
"columnHeaderHeight": { "type": { "name": "number" }, "default": "56" },
- "columnThreshold": { "type": { "name": "number" }, "default": "3" },
"columnVisibilityModel": { "type": { "name": "object" } },
"defaultGroupingExpansionDepth": { "type": { "name": "number" }, "default": "0" },
"density": {
@@ -496,7 +495,7 @@
"returned": "Promise | R"
}
},
- "rowBuffer": { "type": { "name": "number" }, "default": "3" },
+ "rowBufferPx": { "type": { "name": "number" }, "default": "150" },
"rowCount": { "type": { "name": "number" } },
"rowHeight": { "type": { "name": "number" }, "default": "52" },
"rowModesModel": { "type": { "name": "object" } },
@@ -516,7 +515,6 @@
"type": { "name": "enum", "description": "'border'
| 'margin'" },
"default": "\"margin\""
},
- "rowThreshold": { "type": { "name": "number" }, "default": "3" },
"scrollbarSize": { "type": { "name": "number" } },
"scrollEndThreshold": { "type": { "name": "number" }, "default": "80" },
"showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" },
diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json
index 9fd2b885eb548..d9ba3743b0d7c 100644
--- a/docs/pages/x/api/data-grid/data-grid.json
+++ b/docs/pages/x/api/data-grid/data-grid.json
@@ -24,9 +24,8 @@
"checkboxSelection": { "type": { "name": "bool" }, "default": "false" },
"classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } },
"clipboardCopyCellDelimiter": { "type": { "name": "string" }, "default": "'\\t'" },
- "columnBuffer": { "type": { "name": "number" }, "default": "3" },
+ "columnBufferPx": { "type": { "name": "number" }, "default": "150" },
"columnHeaderHeight": { "type": { "name": "number" }, "default": "56" },
- "columnThreshold": { "type": { "name": "number" }, "default": "3" },
"columnVisibilityModel": { "type": { "name": "object" } },
"density": {
"type": {
@@ -413,7 +412,7 @@
"returned": "Promise | R"
}
},
- "rowBuffer": { "type": { "name": "number" }, "default": "3" },
+ "rowBufferPx": { "type": { "name": "number" }, "default": "150" },
"rowCount": { "type": { "name": "number" } },
"rowHeight": { "type": { "name": "number" }, "default": "52" },
"rowModesModel": { "type": { "name": "object" } },
@@ -429,7 +428,6 @@
"type": { "name": "enum", "description": "'border'
| 'margin'" },
"default": "\"margin\""
},
- "rowThreshold": { "type": { "name": "number" }, "default": "3" },
"scrollbarSize": { "type": { "name": "number" } },
"showCellVerticalBorder": { "type": { "name": "bool" }, "default": "false" },
"showColumnVerticalBorder": { "type": { "name": "bool" }, "default": "false" },
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 55da4f984364f..43e271be77231 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
@@ -36,8 +36,8 @@
"clipboardCopyCellDelimiter": {
"description": "The character used to separate cell values when copying to the clipboard."
},
- "columnBuffer": {
- "description": "Number of extra columns to be rendered before/after the visible slice."
+ "columnBufferPx": {
+ "description": "Column region in pixels to render before/after the viewport"
},
"columnHeaderHeight": {
"description": "Sets the height in pixel of the column headers in the Data Grid."
@@ -45,9 +45,6 @@
"columns": {
"description": "Set of columns of type GridColDef[]."
},
- "columnThreshold": {
- "description": "Number of rows from the columnBuffer
that can be visible before a new slice is rendered."
- },
"columnVisibilityModel": {
"description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide
property in GridColDef."
},
@@ -578,9 +575,7 @@
"Promise | R": "The final values to update the row."
}
},
- "rowBuffer": {
- "description": "Number of extra rows to be rendered before/after the visible slice."
- },
+ "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" },
"rowCount": {
"description": "Set the total number of rows, if it is different from the length of the value rows
prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows."
},
@@ -603,9 +598,6 @@
"rowSpacingType": {
"description": "Sets the type of space between rows added by getRowSpacing
."
},
- "rowThreshold": {
- "description": "Number of rows from the rowBuffer
that can be visible before a new slice is rendered."
- },
"scrollbarSize": {
"description": "Override the height/width of the Data Grid inner scrollbar."
},
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 32c54712411fd..714f0c82153de 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
@@ -29,8 +29,8 @@
"clipboardCopyCellDelimiter": {
"description": "The character used to separate cell values when copying to the clipboard."
},
- "columnBuffer": {
- "description": "Number of extra columns to be rendered before/after the visible slice."
+ "columnBufferPx": {
+ "description": "Column region in pixels to render before/after the viewport"
},
"columnHeaderHeight": {
"description": "Sets the height in pixel of the column headers in the Data Grid."
@@ -38,9 +38,6 @@
"columns": {
"description": "Set of columns of type GridColDef[]."
},
- "columnThreshold": {
- "description": "Number of rows from the columnBuffer
that can be visible before a new slice is rendered."
- },
"columnVisibilityModel": {
"description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide
property in GridColDef."
},
@@ -524,9 +521,7 @@
"Promise | R": "The final values to update the row."
}
},
- "rowBuffer": {
- "description": "Number of extra rows to be rendered before/after the visible slice."
- },
+ "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" },
"rowCount": {
"description": "Set the total number of rows, if it is different from the length of the value rows
prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows."
},
@@ -545,9 +540,6 @@
"rowSpacingType": {
"description": "Sets the type of space between rows added by getRowSpacing
."
},
- "rowThreshold": {
- "description": "Number of rows from the rowBuffer
that can be visible before a new slice is rendered."
- },
"scrollbarSize": {
"description": "Override the height/width of the Data Grid inner scrollbar."
},
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 a9dd4e497f260..18b8f9aee4f18 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
@@ -26,8 +26,8 @@
"clipboardCopyCellDelimiter": {
"description": "The character used to separate cell values when copying to the clipboard."
},
- "columnBuffer": {
- "description": "Number of extra columns to be rendered before/after the visible slice."
+ "columnBufferPx": {
+ "description": "Column region in pixels to render before/after the viewport"
},
"columnHeaderHeight": {
"description": "Sets the height in pixel of the column headers in the Data Grid."
@@ -35,9 +35,6 @@
"columns": {
"description": "Set of columns of type GridColDef[]."
},
- "columnThreshold": {
- "description": "Number of rows from the columnBuffer
that can be visible before a new slice is rendered."
- },
"columnVisibilityModel": {
"description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide
property in GridColDef."
},
@@ -427,9 +424,7 @@
"Promise | R": "The final values to update the row."
}
},
- "rowBuffer": {
- "description": "Number of extra rows to be rendered before/after the visible slice."
- },
+ "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" },
"rowCount": {
"description": "Set the total number of rows, if it is different from the length of the value rows
prop. If some rows have children (for instance in the tree data), this number represents the amount of top level rows."
},
@@ -444,9 +439,6 @@
"rowSpacingType": {
"description": "Sets the type of space between rows added by getRowSpacing
."
},
- "rowThreshold": {
- "description": "Number of rows from the rowBuffer
that can be visible before a new slice is rendered."
- },
"scrollbarSize": {
"description": "Override the height/width of the Data Grid inner scrollbar."
},
diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
index 8991449eda96b..9007fa80d6534 100644
--- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
+++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx
@@ -171,10 +171,10 @@ DataGridPremiumRaw.propTypes = {
*/
clipboardCopyCellDelimiter: PropTypes.string,
/**
- * Number of extra columns to be rendered before/after the visible slice.
- * @default 3
+ * Column region in pixels to render before/after the viewport
+ * @default 150
*/
- columnBuffer: PropTypes.number,
+ columnBufferPx: PropTypes.number,
columnGroupingModel: PropTypes.arrayOf(PropTypes.object),
/**
* Sets the height in pixel of the column headers in the Data Grid.
@@ -185,11 +185,6 @@ DataGridPremiumRaw.propTypes = {
* Set of columns of type [[GridColDef]][].
*/
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
- /**
- * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- columnThreshold: PropTypes.number,
/**
* Set the column visibility model of the Data Grid.
* If defined, the Data Grid will ignore the `hide` property in [[GridColDef]].
@@ -889,10 +884,10 @@ DataGridPremiumRaw.propTypes = {
*/
processRowUpdate: PropTypes.func,
/**
- * Number of extra rows to be rendered before/after the visible slice.
- * @default 3
+ * Row region in pixels to render before/after the viewport
+ * @default 150
*/
- rowBuffer: PropTypes.number,
+ rowBufferPx: PropTypes.number,
/**
* Set the total number of rows, if it is different from the length of the value `rows` prop.
* If some rows have children (for instance in the tree data), this number represents the amount of top level rows.
@@ -958,11 +953,6 @@ DataGridPremiumRaw.propTypes = {
* @default "margin"
*/
rowSpacingType: PropTypes.oneOf(['border', 'margin']),
- /**
- * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- rowThreshold: PropTypes.number,
/**
* Override the height/width of the Data Grid inner scrollbar.
*/
diff --git a/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx
index 14267f4ac7dca..63543419ab26c 100644
--- a/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx
+++ b/packages/x-data-grid-premium/src/tests/columns.DataGridPremium.test.tsx
@@ -32,7 +32,7 @@ describe(' - Columns', () => {
columns={[{ field: 'brand' }]}
initialState={{ aggregation: { model: { brand: 'size' } } }}
showCellVerticalBorder
- rowBuffer={1}
+ rowBufferPx={52}
/>
,
);
diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
index df1e21319472d..ca490f839706a 100644
--- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
+++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
@@ -134,10 +134,10 @@ DataGridProRaw.propTypes = {
*/
clipboardCopyCellDelimiter: PropTypes.string,
/**
- * Number of extra columns to be rendered before/after the visible slice.
- * @default 3
+ * Column region in pixels to render before/after the viewport
+ * @default 150
*/
- columnBuffer: PropTypes.number,
+ columnBufferPx: PropTypes.number,
columnGroupingModel: PropTypes.arrayOf(PropTypes.object),
/**
* Sets the height in pixel of the column headers in the Data Grid.
@@ -148,11 +148,6 @@ DataGridProRaw.propTypes = {
* Set of columns of type [[GridColDef]][].
*/
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
- /**
- * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- columnThreshold: PropTypes.number,
/**
* Set the column visibility model of the Data Grid.
* If defined, the Data Grid will ignore the `hide` property in [[GridColDef]].
@@ -791,10 +786,10 @@ DataGridProRaw.propTypes = {
*/
processRowUpdate: PropTypes.func,
/**
- * Number of extra rows to be rendered before/after the visible slice.
- * @default 3
+ * Row region in pixels to render before/after the viewport
+ * @default 150
*/
- rowBuffer: PropTypes.number,
+ rowBufferPx: PropTypes.number,
/**
* Set the total number of rows, if it is different from the length of the value `rows` prop.
* If some rows have children (for instance in the tree data), this number represents the amount of top level rows.
@@ -850,11 +845,6 @@ DataGridProRaw.propTypes = {
* @default "margin"
*/
rowSpacingType: PropTypes.oneOf(['border', 'margin']),
- /**
- * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- rowThreshold: PropTypes.number,
/**
* Override the height/width of the Data Grid inner scrollbar.
*/
diff --git a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts
index 745a4fb63d5d5..0ced8d346ae75 100644
--- a/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts
+++ b/packages/x-data-grid-pro/src/hooks/features/lazyLoader/useGridLazyLoader.ts
@@ -68,12 +68,7 @@ export const useGridLazyLoader = (
privateApiRef: React.MutableRefObject,
props: Pick<
DataGridProProcessedProps,
- | 'onFetchRows'
- | 'rowsLoadingMode'
- | 'pagination'
- | 'paginationMode'
- | 'rowBuffer'
- | 'experimentalFeatures'
+ 'onFetchRows' | 'rowsLoadingMode' | 'pagination' | 'paginationMode' | 'experimentalFeatures'
>,
): void => {
const sortModel = useGridSelector(privateApiRef, gridSortModelSelector);
diff --git a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx
index 511e024d7b53f..bfe5efda3299e 100644
--- a/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/detailPanel.DataGridPro.test.tsx
@@ -59,8 +59,7 @@ describe(' - Detail panel', () => {
getDetailPanelHeight={({ id }) => (Number(id) % 2 === 0 ? 1 : 2) * rowHeight} // 50px for even rows, otherwise 100px
getDetailPanelContent={() => }
rowHeight={rowHeight}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
initialState={{
detailPanel: {
expandedRowIds: [0, 1],
diff --git a/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx
index 9973b2a200b45..eb99be09db6db 100644
--- a/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/infiniteLoader.DataGridPro.test.tsx
@@ -124,27 +124,37 @@ describe(' - Infnite loader', () => {
await waitFor(() => {
expect(getRow.callCount).to.equal(1);
});
- expect(getColumnValues(0)).to.deep.equal(['0', '1']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['0', '1']);
+ });
await waitFor(() => {
expect(getRow.callCount).to.equal(2);
});
- expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['0', '1', '2']);
+ });
await waitFor(() => {
expect(getRow.callCount).to.equal(3);
});
- expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3']);
+ });
await waitFor(() => {
expect(getRow.callCount).to.equal(4);
});
- expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4']);
+ });
await waitFor(() => {
expect(getRow.callCount).to.equal(5);
});
- expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4', '5']);
+ await waitFor(() => {
+ expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4', '5']);
+ });
await sleep(200);
// should not load more rows because the threshold is not reached
diff --git a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
index ece96b663e629..0433592c536bc 100644
--- a/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
+++ b/packages/x-data-grid-pro/src/tests/rows.DataGridPro.test.tsx
@@ -419,7 +419,7 @@ describe(' - Rows', () => {
it('should compute rows correctly on height change', async () => {
const { setProps } = render(
- ,
+ ,
);
expect(getRows()).to.have.length(1);
setProps({
@@ -430,9 +430,10 @@ describe(' - Rows', () => {
expect(getRows()).to.have.length(3);
});
- it('should render last row when scrolling to the bottom', () => {
+ it('should render last row when scrolling to the bottom', async () => {
+ const n = 4;
const rowHeight = 50;
- const rowBuffer = 4;
+ const rowBufferPx = n * rowHeight;
const nbRows = 996;
const height = 600;
render(
@@ -440,7 +441,7 @@ describe(' - Rows', () => {
nbRows={nbRows}
columnHeaderHeight={0}
rowHeight={rowHeight}
- rowBuffer={rowBuffer}
+ rowBufferPx={rowBufferPx}
hideFooter
height={height}
/>,
@@ -451,11 +452,11 @@ describe(' - Rows', () => {
virtualScroller.scrollTop = 10e6; // scroll to the bottom
act(() => virtualScroller.dispatchEvent(new Event('scroll')));
+ clock.runToLast();
+
const lastCell = $$('[role="row"]:last-child [role="gridcell"]')[0];
expect(lastCell).to.have.text('995');
- expect(renderingZone.children.length).to.equal(
- Math.floor((height - 1) / rowHeight) + rowBuffer,
- ); // Subtracting 1 is needed because of the column header borders
+ expect(renderingZone.children.length).to.equal(Math.floor(height / rowHeight) + n);
const scrollbarSize = apiRef.current.state.dimensions.scrollbarSize;
const distanceToFirstRow = (nbRows - renderingZone.children.length) * rowHeight;
expect(gridOffsetTop()).to.equal(distanceToFirstRow);
@@ -475,58 +476,56 @@ describe(' - Rows', () => {
it('should render extra columns when the columnBuffer prop is present', () => {
const border = 1;
const width = 300;
- const columnBuffer = 2;
+ const n = 2;
const columnWidth = 100;
+ const columnBufferPx = n * columnWidth;
render(
,
);
const firstRow = getRow(0);
- expect($$(firstRow, '[role="gridcell"]')).to.have.length(
- Math.floor(width / columnWidth) + columnBuffer,
- );
+ expect($$(firstRow, '[role="gridcell"]')).to.have.length(Math.floor(width / columnWidth) + n);
const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!;
virtualScroller.scrollLeft = 301;
act(() => virtualScroller.dispatchEvent(new Event('scroll')));
+ clock.runToLast();
expect($$(firstRow, '[role="gridcell"]')).to.have.length(
- columnBuffer + 1 + Math.floor(width / columnWidth) + columnBuffer,
+ n + 1 + Math.floor(width / columnWidth) + n,
);
});
- it('should render new rows when scrolling past the rowThreshold value', () => {
- const rowThreshold = 3;
+ it('should render new rows when scrolling past the threshold value', () => {
const rowHeight = 50;
- render(
- ,
- );
+ const rowThresholdPx = 1 * rowHeight;
+ render();
const virtualScroller = document.querySelector('.MuiDataGrid-virtualScroller')!;
const renderingZone = document.querySelector('.MuiDataGrid-virtualScrollerRenderZone')!;
let firstRow = renderingZone.firstChild;
expect(firstRow).to.have.attr('data-rowindex', '0');
- virtualScroller.scrollTop = rowThreshold * rowHeight;
+ virtualScroller.scrollTop = rowThresholdPx;
act(() => virtualScroller.dispatchEvent(new Event('scroll')));
+ clock.runToLast();
firstRow = renderingZone.firstChild;
- expect(firstRow).to.have.attr('data-rowindex', '3');
+ expect(firstRow).to.have.attr('data-rowindex', '1');
});
- it('should render new columns when scrolling past the columnThreshold value', () => {
- const columnThreshold = 3;
+ it('should render new columns when scrolling past the threshold value', () => {
const columnWidth = 100;
- render(
- ,
- );
+ const columnThresholdPx = 1 * columnWidth;
+ render();
const virtualScroller = grid('virtualScroller')!;
const renderingZone = grid('virtualScrollerRenderZone')!;
const firstRow = $(renderingZone, '[role="row"]:first-child')!;
let firstColumn = $$(firstRow, '[role="gridcell"]')[0];
expect(firstColumn).to.have.attr('data-colindex', '0');
- virtualScroller.scrollLeft = columnThreshold * columnWidth;
+ virtualScroller.scrollLeft = columnThresholdPx;
act(() => virtualScroller.dispatchEvent(new Event('scroll')));
+ clock.runToLast();
firstColumn = $(renderingZone, '[role="row"] > [role="gridcell"]')!;
- expect(firstColumn).to.have.attr('data-colindex', '3');
+ expect(firstColumn).to.have.attr('data-colindex', '1');
});
describe('Pagination', () => {
diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx
index fe0f14bbb9d6c..013d06d2cf2c3 100644
--- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx
+++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx
@@ -135,10 +135,10 @@ DataGridRaw.propTypes = {
*/
clipboardCopyCellDelimiter: PropTypes.string,
/**
- * Number of extra columns to be rendered before/after the visible slice.
- * @default 3
+ * Column region in pixels to render before/after the viewport
+ * @default 150
*/
- columnBuffer: PropTypes.number,
+ columnBufferPx: PropTypes.number,
columnGroupingModel: PropTypes.arrayOf(PropTypes.object),
/**
* Sets the height in pixel of the column headers in the Data Grid.
@@ -149,11 +149,6 @@ DataGridRaw.propTypes = {
* Set of columns of type [[GridColDef]][].
*/
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
- /**
- * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- columnThreshold: PropTypes.number,
/**
* Set the column visibility model of the Data Grid.
* If defined, the Data Grid will ignore the `hide` property in [[GridColDef]].
@@ -658,10 +653,10 @@ DataGridRaw.propTypes = {
*/
processRowUpdate: PropTypes.func,
/**
- * Number of extra rows to be rendered before/after the visible slice.
- * @default 3
+ * Row region in pixels to render before/after the viewport
+ * @default 150
*/
- rowBuffer: PropTypes.number,
+ rowBufferPx: PropTypes.number,
/**
* Set the total number of rows, if it is different from the length of the value `rows` prop.
* If some rows have children (for instance in the tree data), this number represents the amount of top level rows.
@@ -705,11 +700,6 @@ DataGridRaw.propTypes = {
* @default "margin"
*/
rowSpacingType: PropTypes.oneOf(['border', 'margin']),
- /**
- * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- rowThreshold: PropTypes.number,
/**
* Override the height/width of the Data Grid inner scrollbar.
*/
diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts
index 3759d21e04241..af9812ee7466a 100644
--- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts
+++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts
@@ -31,10 +31,8 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = {
autoPageSize: false,
checkboxSelection: false,
checkboxSelectionVisibleOnly: false,
- columnBuffer: 3,
- rowBuffer: 3,
- columnThreshold: 3,
- rowThreshold: 3,
+ columnBufferPx: 150,
+ rowBufferPx: 150,
rowSelection: true,
disableColumnFilter: false,
disableColumnMenu: false,
diff --git a/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts b/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts
index 5dc3c3b1c836e..7da63d617fef2 100644
--- a/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts
+++ b/packages/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts
@@ -429,36 +429,6 @@ export function getFirstNonSpannedColumnToRender({
return firstNonSpannedColumnToRender;
}
-export function getFirstColumnIndexToRender({
- firstColumnIndex,
- minColumnIndex,
- columnBuffer,
- firstRowToRender,
- lastRowToRender,
- apiRef,
- visibleRows,
-}: {
- firstColumnIndex: number;
- minColumnIndex: number;
- columnBuffer: number;
- apiRef: React.MutableRefObject;
- firstRowToRender: number;
- lastRowToRender: number;
- visibleRows: GridRowEntry[];
-}) {
- const initialFirstColumnToRender = Math.max(firstColumnIndex - columnBuffer, minColumnIndex);
-
- const firstColumnToRender = getFirstNonSpannedColumnToRender({
- firstColumnToRender: initialFirstColumnToRender,
- apiRef,
- firstRowToRender,
- lastRowToRender,
- visibleRows,
- });
-
- return firstColumnToRender;
-}
-
export function getTotalHeaderHeight(
apiRef: React.MutableRefObject,
headerHeight: number,
diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
index 50c85b23376d7..8ed66d64e1ae8 100644
--- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
+++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
@@ -4,6 +4,8 @@ import {
unstable_useEnhancedEffect as useEnhancedEffect,
unstable_useEventCallback as useEventCallback,
} from '@mui/utils';
+import useLazyRef from '@mui/utils/useLazyRef';
+import useTimeout from '@mui/utils/useTimeout';
import { useTheme, Theme } from '@mui/material/styles';
import type { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity';
import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext';
@@ -43,20 +45,53 @@ import {
} from './gridVirtualizationSelectors';
import { EMPTY_RENDER_CONTEXT } from './useGridVirtualization';
-export const EMPTY_DETAIL_PANELS = Object.freeze(new Map());
-
-export type VirtualScroller = ReturnType;
+const MINIMUM_COLUMN_WIDTH = 50;
interface PrivateApiWithInfiniteLoader
extends GridPrivateApiCommunity,
GridInfiniteLoaderPrivateApi {}
+export type VirtualScroller = ReturnType;
+
+type ScrollPosition = { top: number; left: number };
+enum ScrollDirection {
+ NONE,
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+}
+
+const EMPTY_SCROLL_POSITION = { top: 0, left: 0 };
+
+export const EMPTY_DETAIL_PANELS = Object.freeze(new Map());
+
+const createScrollCache = (
+ rowBufferPx: number,
+ columnBufferPx: number,
+ verticalBuffer: number,
+ horizontalBuffer: number,
+) => ({
+ direction: ScrollDirection.NONE,
+ buffer: bufferForDirection(
+ ScrollDirection.NONE,
+ rowBufferPx,
+ columnBufferPx,
+ verticalBuffer,
+ horizontalBuffer,
+ ),
+});
+type ScrollCache = ReturnType;
+
+const isJSDOM = typeof window !== 'undefined' ? /jsdom/.test(window.navigator.userAgent) : false;
+
export const useGridVirtualScroller = () => {
const apiRef = useGridPrivateApiContext() as React.MutableRefObject;
const rootProps = useGridRootProps();
const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector);
- const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector);
- const enabledForColumns = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector);
+ const enabled = useGridSelector(apiRef, gridVirtualizationEnabledSelector) && !isJSDOM;
+ const enabledForColumns =
+ useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector) && !isJSDOM;
const dimensions = useGridSelector(apiRef, gridDimensionsSelector);
const outerSize = dimensions.viewportOuterSize;
const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector);
@@ -81,11 +116,35 @@ export const useGridVirtualScroller = () => {
useResizeObserver(mainRef, () => apiRef.current.resize());
- const previousContext = React.useRef(EMPTY_RENDER_CONTEXT);
+ /*
+ * Scroll context logic
+ * ====================
+ * We only render the cells contained in the `renderContext`. However, when the user starts scrolling the grid
+ * in a direction, we want to render as many cells as possible in that direction, as to avoid presenting white
+ * areas if the user scrolls too fast/far and the viewport ends up in a region we haven't rendered yet. To render
+ * more cells, we store some offsets to add to the viewport in `scrollCache.buffer`. Those offsets make the render
+ * context wider in the direction the user is going, but also makes the buffer around the viewport `0` for the
+ * dimension (horizontal or vertical) in which the user is not scrolling. So if the normal viewport is 8 columns
+ * wide, with a 1 column buffer (10 columns total), then we want it to be exactly 8 columns wide during vertical
+ * scroll.
+ * However, we don't want the rows in the old context to re-render from e.g. 10 columns to 8 columns, because that's
+ * work that's not necessary. Thus we store the context at the start of the scroll in `frozenContext`, and the rows
+ * that are part of this old context will keep their same render context as to avoid re-rendering.
+ */
+ const scrollPosition = React.useRef(EMPTY_SCROLL_POSITION);
+ const previousContextScrollPosition = React.useRef(EMPTY_SCROLL_POSITION);
const previousRowContext = React.useRef(EMPTY_RENDER_CONTEXT);
const renderContext = useGridSelector(apiRef, gridRenderContextSelector);
- const scrollPosition = React.useRef({ top: 0, left: 0 }).current;
- const prevTotalWidth = React.useRef(columnsTotalWidth);
+ const scrollTimeout = useTimeout();
+ const frozenContext = React.useRef(undefined);
+ const scrollCache = useLazyRef(() =>
+ createScrollCache(
+ rootProps.rowBufferPx,
+ rootProps.columnBufferPx,
+ dimensions.rowHeight * 15,
+ MINIMUM_COLUMN_WIDTH * 6,
+ ),
+ ).current;
const focusedCell = {
rowIndex: React.useMemo(
@@ -100,7 +159,7 @@ export const useGridVirtualScroller = () => {
};
const updateRenderContext = React.useCallback(
- (nextRenderContext: GridRenderContext, rawRenderContext: GridRenderContext) => {
+ (nextRenderContext: GridRenderContext) => {
if (
areRenderContextsEqual(nextRenderContext, apiRef.current.state.virtualization.renderContext)
) {
@@ -129,62 +188,90 @@ export const useGridVirtualScroller = () => {
apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext);
}
- previousContext.current = rawRenderContext;
- prevTotalWidth.current = dimensions.columnsTotalWidth;
+ previousContextScrollPosition.current = scrollPosition.current;
},
- [apiRef, dimensions.isReady, dimensions.columnsTotalWidth],
+ [apiRef, dimensions.isReady],
);
const triggerUpdateRenderContext = () => {
- const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns);
- const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition);
+ const newScroll = {
+ top: scrollerRef.current!.scrollTop,
+ left: scrollerRef.current!.scrollLeft,
+ };
- // Since previous render, we have scrolled...
- const topRowsScrolled = Math.abs(
- rawRenderContext.firstRowIndex - previousContext.current.firstRowIndex,
- );
- const bottomRowsScrolled = Math.abs(
- rawRenderContext.lastRowIndex - previousContext.current.lastRowIndex,
- );
+ const dx = newScroll.left - scrollPosition.current.left;
+ const dy = newScroll.top - scrollPosition.current.top;
+
+ const isScrolling = dx !== 0 || dy !== 0;
+
+ scrollPosition.current = newScroll;
- const topColumnsScrolled = Math.abs(
- rawRenderContext.firstColumnIndex - previousContext.current.firstColumnIndex,
+ const direction = isScrolling ? directionForDelta(dx, dy) : ScrollDirection.NONE;
+
+ // Since previous render, we have scrolled...
+ const rowScroll = Math.abs(
+ scrollPosition.current.top - previousContextScrollPosition.current.top,
);
- const bottomColumnsScrolled = Math.abs(
- rawRenderContext.lastColumnIndex - previousContext.current.lastColumnIndex,
+ const columnScroll = Math.abs(
+ scrollPosition.current.left - previousContextScrollPosition.current.left,
);
- const shouldUpdate =
- topRowsScrolled >= rootProps.rowThreshold ||
- bottomRowsScrolled >= rootProps.rowThreshold ||
- topColumnsScrolled >= rootProps.columnThreshold ||
- bottomColumnsScrolled >= rootProps.columnThreshold ||
- prevTotalWidth.current !== dimensions.columnsTotalWidth;
+ // PERF: use the computed minimum column width instead of a static one
+ const didCrossThreshold =
+ rowScroll >= dimensions.rowHeight || columnScroll >= MINIMUM_COLUMN_WIDTH;
+ const didChangeDirection = scrollCache.direction !== direction;
+ const shouldUpdate = didCrossThreshold || didChangeDirection;
if (!shouldUpdate) {
- return previousContext.current;
+ return renderContext;
+ }
+
+ // Render a new context
+
+ if (didChangeDirection) {
+ switch (direction) {
+ case ScrollDirection.NONE:
+ case ScrollDirection.LEFT:
+ case ScrollDirection.RIGHT:
+ frozenContext.current = undefined;
+ break;
+ default:
+ frozenContext.current = renderContext;
+ break;
+ }
}
+ scrollCache.direction = direction;
+ scrollCache.buffer = bufferForDirection(
+ direction,
+ rootProps.rowBufferPx,
+ rootProps.columnBufferPx,
+ dimensions.rowHeight * 15,
+ MINIMUM_COLUMN_WIDTH * 6,
+ );
+
+ const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns);
+ const nextRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache);
+
// Prevents batching render context changes
ReactDOM.flushSync(() => {
- updateRenderContext(nextRenderContext, rawRenderContext);
+ updateRenderContext(nextRenderContext);
});
+ scrollTimeout.start(1000, triggerUpdateRenderContext);
+
return nextRenderContext;
};
const forceUpdateRenderContext = () => {
const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns);
- const [nextRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition);
- updateRenderContext(nextRenderContext, rawRenderContext);
+ const nextRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache);
+ updateRenderContext(nextRenderContext);
};
const handleScroll = useEventCallback((event: React.UIEvent) => {
const { scrollTop, scrollLeft } = event.currentTarget;
- scrollPosition.top = scrollTop;
- scrollPosition.left = scrollLeft;
-
// On iOS and macOS, negative offsets are possible when swiping past the start
if (scrollTop < 0) {
return;
@@ -228,8 +315,7 @@ export const useGridVirtualScroller = () => {
return [];
}
- const columnPositions = gridColumnPositionsSelector(apiRef);
- const currentRenderContext = params.renderContext ?? renderContext;
+ const baseRenderContext = params.renderContext ?? renderContext;
const isLastSection =
(!hasBottomPinnedRows && params.position === undefined) ||
@@ -253,8 +339,8 @@ export const useGridVirtualScroller = () => {
const rowModels = params.rows ?? currentPage.rows;
- const firstRowToRender = currentRenderContext.firstRowIndex;
- const lastRowToRender = Math.min(currentRenderContext.lastRowIndex, rowModels.length);
+ const firstRowToRender = baseRenderContext.firstRowIndex;
+ const lastRowToRender = Math.min(baseRenderContext.lastRowIndex, rowModels.length);
const rowIndexes = params.rows
? range(0, params.rows.length)
@@ -274,6 +360,7 @@ export const useGridVirtualScroller = () => {
const rows: React.ReactNode[] = [];
const rowProps = rootProps.slotProps?.row;
+ const columnPositions = gridColumnPositionsSelector(apiRef);
rowIndexes.forEach((rowIndexInPage) => {
const { id, model } = rowModels[rowIndexInPage];
@@ -350,6 +437,16 @@ export const useGridVirtualScroller = () => {
tabbableCell = cellParams.cellMode === 'view' ? cellTabIndex.field : null;
}
+ let currentRenderContext = baseRenderContext;
+ if (
+ !isPinnedSection &&
+ frozenContext.current &&
+ rowIndexInPage >= frozenContext.current.firstRowIndex &&
+ rowIndexInPage < frozenContext.current.lastRowIndex
+ ) {
+ currentRenderContext = frozenContext.current;
+ }
+
const offsetLeft = computeOffsetLeft(
columnPositions,
currentRenderContext,
@@ -453,12 +550,12 @@ export const useGridVirtualScroller = () => {
useRunOnce(outerSize.width !== 0, () => {
const inputs = inputsSelector(apiRef, rootProps, enabled, enabledForColumns);
- const [initialRenderContext, rawRenderContext] = computeRenderContext(inputs, scrollPosition);
- updateRenderContext(initialRenderContext, rawRenderContext);
+ const initialRenderContext = computeRenderContext(inputs, scrollPosition.current, scrollCache);
+ updateRenderContext(initialRenderContext);
apiRef.current.publishEvent('scrollPositionChange', {
- top: scrollPosition.top,
- left: scrollPosition.left,
+ top: scrollPosition.current.top,
+ left: scrollPosition.current.left,
renderContext: initialRenderContext,
});
});
@@ -497,18 +594,19 @@ export const useGridVirtualScroller = () => {
};
};
-type ScrollPosition = { top: number; left: number };
type RenderContextInputs = {
enabled: boolean;
enabledForColumns: boolean;
apiRef: React.MutableRefObject;
autoHeight: boolean;
- rowBuffer: number;
- columnBuffer: number;
+ rowBufferPx: number;
+ columnBufferPx: number;
leftPinnedWidth: number;
columnsTotalWidth: number;
viewportInnerWidth: number;
viewportInnerHeight: number;
+ lastRowHeight: number;
+ lastColumnWidth: number;
rowsMeta: ReturnType;
columnPositions: ReturnType;
rows: ReturnType['rows'];
@@ -525,27 +623,36 @@ function inputsSelector(
): RenderContextInputs {
const dimensions = gridDimensionsSelector(apiRef.current.state);
const currentPage = getVisibleRows(apiRef, rootProps);
+ const visibleColumns = gridVisibleColumnDefinitionsSelector(apiRef);
+ const lastRowId = apiRef.current.state.rows.dataRowIds.at(-1);
+ const lastColumn = visibleColumns.at(-1);
return {
enabled,
enabledForColumns,
apiRef,
autoHeight: rootProps.autoHeight,
- rowBuffer: rootProps.rowBuffer,
- columnBuffer: rootProps.columnBuffer,
+ rowBufferPx: rootProps.rowBufferPx,
+ columnBufferPx: rootProps.columnBufferPx,
leftPinnedWidth: dimensions.leftPinnedWidth,
columnsTotalWidth: dimensions.columnsTotalWidth,
viewportInnerWidth: dimensions.viewportInnerSize.width,
viewportInnerHeight: dimensions.viewportInnerSize.height,
+ lastRowHeight: lastRowId !== undefined ? apiRef.current.unstable_getRowHeight(lastRowId) : 0,
+ lastColumnWidth: lastColumn?.computedWidth ?? 0,
rowsMeta: gridRowsMetaSelector(apiRef.current.state),
columnPositions: gridColumnPositionsSelector(apiRef),
rows: currentPage.rows,
range: currentPage.range,
pinnedColumns: gridVisiblePinnedColumnDefinitionsSelector(apiRef),
- visibleColumns: gridVisibleColumnDefinitionsSelector(apiRef),
+ visibleColumns,
};
}
-function computeRenderContext(inputs: RenderContextInputs, scrollPosition: ScrollPosition) {
+function computeRenderContext(
+ inputs: RenderContextInputs,
+ scrollPosition: ScrollPosition,
+ scrollCache: ScrollCache,
+) {
let renderContext: GridRenderContext;
if (!inputs.enabled) {
@@ -562,7 +669,11 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol
// Clamp the value because the search may return an index out of bounds.
// In the last index, this is not needed because Array.slice doesn't include it.
const firstRowIndex = Math.min(
- getNearestIndexToRender(inputs, top),
+ getNearestIndexToRender(inputs, top, {
+ atStart: true,
+ lastPosition:
+ inputs.rowsMeta.positions[inputs.rowsMeta.positions.length - 1] + inputs.lastRowHeight,
+ }),
inputs.rowsMeta.positions.length - 1,
);
@@ -581,7 +692,10 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol
lastIndex: lastRowIndex,
minFirstIndex: 0,
maxLastIndex: inputs.rows.length,
- buffer: inputs.rowBuffer,
+ bufferBefore: scrollCache.buffer.rowBefore,
+ bufferAfter: scrollCache.buffer.rowAfter,
+ positions: inputs.rowsMeta.positions,
+ lastSize: inputs.lastRowHeight,
});
for (let i = firstRowToRender; i < lastRowToRender && !hasRowWithAutoHeight; i += 1) {
@@ -609,20 +723,16 @@ function computeRenderContext(inputs: RenderContextInputs, scrollPosition: Scrol
};
}
- const actualRenderContext = deriveRenderContext(
- inputs.apiRef,
- inputs.rowBuffer,
- inputs.columnBuffer,
- inputs.rows,
- inputs.pinnedColumns,
- inputs.visibleColumns,
- renderContext,
- );
+ const actualRenderContext = deriveRenderContext(inputs, renderContext, scrollCache);
- return [actualRenderContext, renderContext];
+ return actualRenderContext;
}
-function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) {
+function getNearestIndexToRender(
+ inputs: RenderContextInputs,
+ offset: number,
+ options?: SearchOptions,
+) {
const lastMeasuredIndexRelativeToAllRows = inputs.apiRef.current.getLastMeasuredRowIndex();
let allRowsMeasured = lastMeasuredIndexRelativeToAllRows === Infinity;
if (inputs.range?.lastRowIndex && !allRowsMeasured) {
@@ -642,7 +752,7 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) {
) {
// If all rows were measured (when no row has "auto" as height) or all rows before the offset
// were measured, then use a binary search because it's faster.
- return binarySearch(offset, inputs.rowsMeta.positions);
+ return binarySearch(offset, inputs.rowsMeta.positions, options);
}
// Otherwise, use an exponential search.
@@ -653,6 +763,7 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) {
offset,
inputs.rowsMeta.positions,
lastMeasuredIndexRelativeToCurrentPage,
+ options,
);
}
@@ -662,36 +773,38 @@ function getNearestIndexToRender(inputs: RenderContextInputs, offset: number) {
* spanning.
*/
function deriveRenderContext(
- apiRef: React.MutableRefObject,
- rowBuffer: number,
- columnBuffer: number,
- rows: ReturnType['rows'],
- pinnedColumns: ReturnType,
- visibleColumns: ReturnType,
+ inputs: RenderContextInputs,
nextRenderContext: GridRenderContext,
+ scrollCache: ScrollCache,
) {
const [firstRowToRender, lastRowToRender] = getIndexesToRender({
firstIndex: nextRenderContext.firstRowIndex,
lastIndex: nextRenderContext.lastRowIndex,
minFirstIndex: 0,
- maxLastIndex: rows.length,
- buffer: rowBuffer,
+ maxLastIndex: inputs.rows.length,
+ bufferBefore: scrollCache.buffer.rowBefore,
+ bufferAfter: scrollCache.buffer.rowAfter,
+ positions: inputs.rowsMeta.positions,
+ lastSize: inputs.lastRowHeight,
});
const [initialFirstColumnToRender, lastColumnToRender] = getIndexesToRender({
firstIndex: nextRenderContext.firstColumnIndex,
lastIndex: nextRenderContext.lastColumnIndex,
- minFirstIndex: pinnedColumns.left.length,
- maxLastIndex: visibleColumns.length - pinnedColumns.right.length,
- buffer: columnBuffer,
+ minFirstIndex: inputs.pinnedColumns.left.length,
+ maxLastIndex: inputs.visibleColumns.length - inputs.pinnedColumns.right.length,
+ bufferBefore: scrollCache.buffer.columnBefore,
+ bufferAfter: scrollCache.buffer.columnAfter,
+ positions: inputs.columnPositions,
+ lastSize: inputs.lastColumnWidth,
});
const firstColumnToRender = getFirstNonSpannedColumnToRender({
firstColumnToRender: initialFirstColumnToRender,
- apiRef,
+ apiRef: inputs.apiRef,
firstRowToRender,
lastRowToRender,
- visibleRows: rows,
+ visibleRows: inputs.rows,
});
return {
@@ -745,7 +858,12 @@ function binarySearch(
: binarySearch(offset, positions, options, pivot + 1, sliceEnd);
}
-function exponentialSearch(offset: number, positions: number[], index: number): number {
+function exponentialSearch(
+ offset: number,
+ positions: number[],
+ index: number,
+ options: SearchOptions | undefined = undefined,
+): number {
let interval = 1;
while (index < positions.length && Math.abs(positions[index]) < offset) {
@@ -756,7 +874,7 @@ function exponentialSearch(offset: number, positions: number[], index: number):
return binarySearch(
offset,
positions,
- undefined,
+ options,
Math.floor(index / 2),
Math.min(index, positions.length),
);
@@ -765,19 +883,35 @@ function exponentialSearch(offset: number, positions: number[], index: number):
function getIndexesToRender({
firstIndex,
lastIndex,
- buffer,
+ bufferBefore,
+ bufferAfter,
minFirstIndex,
maxLastIndex,
+ positions,
+ lastSize,
}: {
firstIndex: number;
lastIndex: number;
- buffer: number;
+ bufferBefore: number;
+ bufferAfter: number;
minFirstIndex: number;
maxLastIndex: number;
+ positions: number[];
+ lastSize: number;
}) {
+ const firstPosition = positions[firstIndex] - bufferBefore;
+ const lastPosition = positions[lastIndex] + bufferAfter;
+
+ const firstIndexPadded = binarySearch(firstPosition, positions, {
+ atStart: true,
+ lastPosition: positions[positions.length - 1] + lastSize,
+ });
+
+ const lastIndexPadded = binarySearch(lastPosition, positions);
+
return [
- clamp(firstIndex - buffer, minFirstIndex, maxLastIndex),
- clamp(lastIndex + buffer, minFirstIndex, maxLastIndex),
+ clamp(firstIndexPadded, minFirstIndex, maxLastIndex),
+ clamp(lastIndexPadded, minFirstIndex, maxLastIndex),
];
}
@@ -806,3 +940,73 @@ export function computeOffsetLeft(
return left;
}
+
+function directionForDelta(dx: number, dy: number) {
+ if (dx === 0 && dy === 0) {
+ return ScrollDirection.NONE;
+ }
+ /* eslint-disable */
+ if (Math.abs(dy) >= Math.abs(dx)) {
+ if (dy > 0) {
+ return ScrollDirection.DOWN;
+ } else {
+ return ScrollDirection.UP;
+ }
+ } else {
+ if (dx > 0) {
+ return ScrollDirection.RIGHT;
+ } else {
+ return ScrollDirection.LEFT;
+ }
+ }
+ /* eslint-enable */
+}
+
+function bufferForDirection(
+ direction: ScrollDirection,
+ rowBufferPx: number,
+ columnBufferPx: number,
+ verticalBuffer: number,
+ horizontalBuffer: number,
+) {
+ switch (direction) {
+ case ScrollDirection.NONE:
+ return {
+ rowAfter: rowBufferPx,
+ rowBefore: rowBufferPx,
+ columnAfter: columnBufferPx,
+ columnBefore: columnBufferPx,
+ };
+ case ScrollDirection.LEFT:
+ return {
+ rowAfter: 0,
+ rowBefore: 0,
+ columnAfter: 0,
+ columnBefore: horizontalBuffer,
+ };
+ case ScrollDirection.RIGHT:
+ return {
+ rowAfter: 0,
+ rowBefore: 0,
+ columnAfter: horizontalBuffer,
+ columnBefore: 0,
+ };
+ case ScrollDirection.UP:
+ return {
+ rowAfter: 0,
+ rowBefore: verticalBuffer,
+ columnAfter: 0,
+ columnBefore: 0,
+ };
+ case ScrollDirection.DOWN:
+ return {
+ rowAfter: verticalBuffer,
+ rowBefore: 0,
+ columnAfter: 0,
+ columnBefore: 0,
+ };
+ default:
+ // eslint unable to figure out enum exhaustiveness
+ throw new Error('unreachable');
+ }
+}
diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts
index 13918cd9b5ab5..eca76ffebad09 100644
--- a/packages/x-data-grid/src/models/props/DataGridProps.ts
+++ b/packages/x-data-grid/src/models/props/DataGridProps.ts
@@ -128,30 +128,20 @@ export interface DataGridPropsWithDefaultValues {
*/
checkboxSelectionVisibleOnly: boolean;
/**
- * Number of extra columns to be rendered before/after the visible slice.
- * @default 3
+ * Column region in pixels to render before/after the viewport
+ * @default 150
*/
- columnBuffer: number;
+ columnBufferPx: number;
/**
- * Number of extra rows to be rendered before/after the visible slice.
- * @default 3
+ * Row region in pixels to render before/after the viewport
+ * @default 150
*/
- rowBuffer: number;
+ rowBufferPx: number;
/**
* If `false`, the row selection mode is disabled.
* @default true
*/
rowSelection: boolean;
- /**
- * Number of rows from the `rowBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- rowThreshold: number;
- /**
- * Number of rows from the `columnBuffer` that can be visible before a new slice is rendered.
- * @default 3
- */
- columnThreshold: number;
/**
* If `true`, column filters are disabled.
* @default false
diff --git a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx
index 57f591f6f573b..25071ffe04e88 100644
--- a/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/columnSpanning.DataGrid.test.tsx
@@ -312,8 +312,7 @@ describe(' - Column spanning', () => {
{ field: 'price' },
]}
rows={rows}
- rowBuffer={1}
- rowThreshold={1}
+ rowBufferPx={rowHeight}
rowHeight={rowHeight}
/>
,
@@ -348,8 +347,7 @@ describe(' - Column spanning', () => {
{ field: 'col3', width: 100 },
]}
rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3' }]}
- columnBuffer={1}
- columnThreshold={1}
+ columnBufferPx={100}
/>
,
);
@@ -456,8 +454,7 @@ describe(' - Column spanning', () => {
{ field: 'col4', width: 100 },
]}
rows={[{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4' }]}
- columnBuffer={1}
- columnThreshold={1}
+ columnBufferPx={100}
/>
,
);
@@ -743,8 +740,7 @@ describe(' - Column spanning', () => {
{ id: 0, col0: '0-0', col1: '0-1', col2: '0-2', col3: '0-3', col4: '0-4', col5: '0-5' },
{ id: 1, col0: '1-0', col1: '1-1', col2: '1-2', col3: '1-3', col4: '1-4', col5: '1-5' },
]}
- columnBuffer={1}
- columnThreshold={1}
+ columnBufferPx={100}
/>
,
);
@@ -803,10 +799,8 @@ describe(' - Column spanning', () => {
{ id: 5, col0: '5-0', col1: '5-1', col2: '5-2', col3: '5-3', col4: '5-4', col5: '5-5' },
{ id: 6, col0: '6-0', col1: '6-1', col2: '6-2', col3: '6-3', col4: '6-4', col5: '6-5' },
]}
- columnBuffer={1}
- columnThreshold={1}
- rowBuffer={1}
- rowThreshold={1}
+ columnBufferPx={100}
+ rowBufferPx={50}
rowHeight={rowHeight}
/>
,
@@ -828,6 +822,7 @@ describe(' - Column spanning', () => {
// hide first row to trigger row virtualization
virtualScroller.scrollTop = rowHeight + 10;
virtualScroller.dispatchEvent(new Event('scroll'));
+ clock.runToLast();
expect(getCell(2, 5).offsetLeft).to.equal(
getCell(1, 5).offsetLeft,
@@ -918,10 +913,8 @@ describe(' - Column spanning', () => {
col5: '5-5',
},
]}
- columnBuffer={1}
- columnThreshold={1}
- rowBuffer={1}
- rowThreshold={1}
+ columnBufferPx={100}
+ rowBufferPx={50}
rowHeight={rowHeight}
/>
diff --git a/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx b/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx
index 3508850d91a8a..6fccae286deea 100644
--- a/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/keyboard.DataGrid.test.tsx
@@ -57,7 +57,7 @@ describe(' - Keyboard', () => {
columns={transformColSizes(data.columns)}
initialState={{ pagination: { paginationModel: { pageSize: PAGE_SIZE } } }}
pageSizeOptions={[PAGE_SIZE]}
- rowBuffer={PAGE_SIZE}
+ rowBufferPx={PAGE_SIZE * ROW_HEIGHT}
rowHeight={ROW_HEIGHT}
columnHeaderHeight={HEADER_HEIGHT}
hideFooter
@@ -485,7 +485,7 @@ describe(' - Keyboard', () => {
columns={transformColSizes(data.columns)}
paginationModel={{ pageSize: PAGE_SIZE, page: 0 }}
pageSizeOptions={[PAGE_SIZE]}
- rowBuffer={PAGE_SIZE}
+ rowBufferPx={PAGE_SIZE * ROW_HEIGHT}
rowHeight={ROW_HEIGHT}
columnHeaderHeight={HEADER_HEIGHT}
hideFooter
diff --git a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
index 52b7342ccb617..468d5709d28a4 100644
--- a/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/layout.DataGrid.test.tsx
@@ -1202,8 +1202,6 @@ describe(' - Layout & warnings', () => {
}).toErrorDev([
'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.',
'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.',
- 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.',
- 'Warning: Encountered two children with the same key, `id`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.',
]);
});
diff --git a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
index 12a40be44b724..3993d846fb4bd 100644
--- a/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
+++ b/packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
@@ -663,7 +663,7 @@ describe(' - Rows', () => {
height={columnHeaderHeight + 20 + border * 2} // Force to only measure the first row
getBioContentHeight={() => measuredRowHeight}
getRowHeight={() => 'auto'}
- rowBuffer={0}
+ rowBufferPx={0}
/>,
);
const virtualScrollerContent = document.querySelector(
@@ -693,7 +693,7 @@ describe(' - Rows', () => {
getBioContentHeight={() => measuredRowHeight}
getEstimatedRowHeight={() => estimatedRowHeight}
getRowHeight={() => 'auto'}
- rowBuffer={0}
+ rowBufferPx={0}
/>,
);
const virtualScrollerContent = document.querySelector(
@@ -716,7 +716,7 @@ describe(' - Rows', () => {
getBioContentHeight={(row) => (row.expanded ? 200 : 100)}
rows={[{ clientId: 'c1', expanded: false }]}
getRowHeight={() => 'auto'}
- rowBuffer={0}
+ rowBufferPx={0}
/>,
);
const virtualScrollerContent = document.querySelector(
@@ -742,7 +742,7 @@ describe(' - Rows', () => {
50}
getRowHeight={({ id }) => (id === 'c3' ? 100 : 'auto')}
- rowBuffer={0}
+ rowBufferPx={0}
/>,
);
expect(getRow(0)).toHaveInlineStyle({ minHeight: 'auto' });
@@ -756,8 +756,7 @@ describe(' - Rows', () => {
rows={baselineProps.rows.slice(0, 1)}
getBioContentHeight={() => 100}
getRowHeight={() => 'auto'}
- columnBuffer={0}
- columnThreshold={0}
+ columnBufferPx={0}
width={100}
/>,
);
@@ -771,8 +770,7 @@ describe(' - Rows', () => {
100}
getRowHeight={() => 'auto'}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
columnHeaderHeight={columnHeaderHeight}
height={columnHeaderHeight + 52 + border * 2}
/>,
@@ -807,8 +805,7 @@ describe(' - Rows', () => {
getRowHeight={({ id }) => (id === 'c1' ? 'auto' : null)}
density="comfortable"
rows={baselineProps.rows.slice(0, 2)}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
columnHeaderHeight={columnHeaderHeight}
/>,
);
@@ -835,8 +832,7 @@ describe(' - Rows', () => {
measuredRowHeight}
getRowHeight={() => 'auto'}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
columnHeaderHeight={columnHeaderHeight}
getRowId={(row) => row.id}
hideFooter={false}
@@ -863,8 +859,7 @@ describe(' - Rows', () => {
measuredRowHeight}
getRowHeight={() => 'auto'}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
columnHeaderHeight={columnHeaderHeight}
getRowId={(row) => row.id}
hideFooter={false}
@@ -892,8 +887,7 @@ describe(' - Rows', () => {
measuredRowHeight}
getRowHeight={() => 'auto'}
- rowBuffer={0}
- rowThreshold={0}
+ rowBufferPx={0}
columnHeaderHeight={columnHeaderHeight}
getRowId={(row) => row.id}
hideFooter={false}
diff --git a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx
index fa9f918881536..57f00d3c8af01 100644
--- a/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx
+++ b/test/e2e/fixtures/DataGridPro/KeyboardNavigationFocus.tsx
@@ -13,7 +13,7 @@ export default function KeyboardNavigationFocus() {
initial focus
-
+
);