[DataGridPro] Data source nested pagination recipe
Allows the pagination of any nested level of the tree data. A possible solution for #14527 in the userland
https://deploy-preview-14777--material-ui-x.netlify.app/x/react-data-grid/server-side-data/recipes/
In progress
- [x] Refine behavior with filtering, sorting, etc.
- [ ] ~~Check if the cache could be integrated with it~~ it could not
- [x] Optional: Retain the
paginationModelstate for each nested level. - [ ] ~~Optional: Retain unique
filterModelandsortModelstates for each nested level.~~ makes more sense without it - [x] List the limitations of the recipe
Follow-up
- [ ] Implement with row grouping
Deploy preview: https://deploy-preview-14777--material-ui-x.netlify.app/
Updated pages:
- docs/data/data-grid/server-side-data/recipes.md
- docs/data/data-grid/server-side-data/lazy-loading.md
Bundle size report
Total Size Change: 🔺+114B(0.00%) - Total Gzip Change: 🔺+22B(0.00%) Files: 122 total (0 added, 0 removed, 6 changed)
Show details for 100 more bundles (22 more not shown)
@mui/x-data-grid parsed: 🔺+19B(0.00%) gzip: 🔺+3B(0.00%) @mui/x-data-grid-premium parsed: 🔺+19B(0.00%) gzip: 🔺+1B(0.00%) @mui/x-data-grid-premium/DataGridPremium parsed: 🔺+19B(0.00%) gzip: 🔺+2B(0.00%) @mui/x-data-grid-pro parsed: 🔺+19B(0.00%) gzip: 🔺+8B(+0.01%) @mui/x-data-grid-pro/DataGridPro parsed: 🔺+19B(0.00%) gzip: 🔺+3B(0.00%) @mui/x-data-grid/DataGrid parsed: 🔺+19B(+0.01%) gzip: 🔺+5B(0.00%) @mui/x-charts parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/BarChartPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ChartContainerPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ChartDataProviderPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ChartsToolbarPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ChartZoomSlider parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/FunnelChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/Heatmap parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/LineChartPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/PieChartPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/RadarChartPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ScatterChartPro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/BarChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartContainer parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartDataProvider parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsAxis parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsAxisHighlight parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsClipPath parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsGrid parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLabel parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLegend parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLocalizationProvider parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsOverlay parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsReferenceLine parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsSurface parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsText parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsTooltip parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsXAxis parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsYAxis parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/Gauge parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/LineChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/PieChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/RadarChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ScatterChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/SparkLineChart parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/Toolbar parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDateFns parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDateFnsJalali parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDayjs parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterLuxon parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMoment parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMomentHijri parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMomentJalaali parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangeCalendar parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangePickerDay parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangePickerDay2 parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateTimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DesktopDateRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DesktopDateTimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DesktopTimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/LocalizationProvider parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MobileDateRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MobileDateTimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MobileTimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MultiInputDateRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MultiInputDateTimeRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MultiInputTimeRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/PickersRangeCalendarHeader parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputDateRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputDateTimeRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputTimeRangeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/StaticDateRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/TimeRangePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDateFns parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDateFnsBase parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDateFnsJalali parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDayjs parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterLuxon parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMoment parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMomentHijri parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMomentJalaali parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateCalendar parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DatePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateTimeField parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateTimePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DayCalendarSkeleton parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopDatePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopDateTimePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopTimePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DigitalClock parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/LocalizationProvider parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileDatePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileDateTimePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileTimePicker parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MonthCalendar parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MultiSectionDigitalClock parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickerDay2 parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickersActionBar parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickersCalendarHeader parsed: 0B(0.00%) gzip: 0B(0.00%)
Generated by :no_entry_sign: dangerJS against a4bf79980da41fcf94ece3b5bab78a675cf50945
Looking good, noticed one issue where top level items are temporarily nested under the newly expanded row whilst the children are loading:
This pull request has conflicts, please resolve those before we can evaluate the pull request.
Thanks for adding a type label to the PR! 👍
I have noticed that the data source is called twice if you change the expansion after the page is being changed
https://github.com/user-attachments/assets/27f7f41a-5e05-44ff-b540-ce86682328b8
I have noticed that the data source is called twice if you change the expansion after the page is being changed
This happens because we maintain separate pagination states for each nested level and reset them when you switch levels.
The first dataSource call occurs due to the dataSource instance being updated, and the second happens when we set the pagination state (paginationModel)
Other than making an additional API call, this shouldn’t cause any issues, because the second call simply overrides the first.
We could avoid this by not keeping separate pagination state for each level, but that would result in a less convenient UX. So in this context, I think trading off a single extra call for a better UX is reasonable.
What do you think?
So in this context, I think trading off a single extra call for a better UX is reasonable.
Agree, since the demo should not take care of this. It should be handled internally
Maybe having debounced fetch row here would help https://github.com/mui/mui-x/blob/v8.5.2/packages/x-data-grid/src/hooks/features/dataSource/useGridDataSourceBase.ts#L272
The proper way would be implementing https://github.com/mui/mui-x/issues/18253
In any case, I am fine with merging this recipe like it is now. Not sure if you want @mapache-salvaje to check the small docs updates that were made.
This pull request has conflicts, please resolve those before we can evaluate the pull request.
@mapache-salvaje I merged this one since the changes were not huge, feel free to leave your feedback on documentation aspect of it if you want, and I'll accommodate it in the follow-up PR.