11import * as React from 'react' ;
2- import { DataGrid , GridRowId , GridPaginationModel } from '@mui/x-data-grid' ;
2+ import {
3+ DataGrid ,
4+ GridRowId ,
5+ GridPaginationModel ,
6+ GridPaginationMeta ,
7+ } from '@mui/x-data-grid' ;
8+ import Radio from '@mui/material/Radio' ;
9+ import RadioGroup from '@mui/material/RadioGroup' ;
10+ import FormControlLabel from '@mui/material/FormControlLabel' ;
11+ import FormControl from '@mui/material/FormControl' ;
12+ import FormLabel from '@mui/material/FormLabel' ;
313import { createFakeServer } from '@mui/x-data-grid-generator' ;
414
515const PAGE_SIZE = 5 ;
@@ -10,7 +20,11 @@ const SERVER_OPTIONS = {
1020
1121const { useQuery, ...data } = createFakeServer ( { } , SERVER_OPTIONS ) ;
1222
23+ type RowCountType = 'known' | 'unknown' | 'estimated' ;
24+
1325export default function CursorPaginationGrid ( ) {
26+ const [ rowCountType , setRowCountType ] = React . useState < RowCountType > ( 'known' ) ;
27+
1428 const mapPageToNextCursor = React . useRef < { [ page : number ] : GridRowId } > ( { } ) ;
1529
1630 const [ paginationModel , setPaginationModel ] = React . useState ( {
@@ -25,7 +39,11 @@ export default function CursorPaginationGrid() {
2539 } ) ,
2640 [ paginationModel ] ,
2741 ) ;
28- const { isLoading, rows, pageInfo } = useQuery ( queryOptions ) ;
42+ const {
43+ isLoading,
44+ rows,
45+ pageInfo : { hasNextPage, nextCursor, totalRowCount } ,
46+ } = useQuery ( queryOptions ) ;
2947
3048 const handlePaginationModelChange = ( newPaginationModel : GridPaginationModel ) => {
3149 // We have the cursor, we can allow the page transition.
@@ -37,38 +55,94 @@ export default function CursorPaginationGrid() {
3755 }
3856 } ;
3957
58+ const paginationMetaRef = React . useRef < GridPaginationMeta > ( ) ;
59+
60+ // Memoize to avoid flickering when the `hasNextPage` is `undefined` during refetch
61+ const paginationMeta = React . useMemo ( ( ) => {
62+ if (
63+ hasNextPage !== undefined &&
64+ paginationMetaRef . current ?. hasNextPage !== hasNextPage
65+ ) {
66+ paginationMetaRef . current = { hasNextPage } ;
67+ }
68+ return paginationMetaRef . current ;
69+ } , [ hasNextPage ] ) ;
70+
4071 React . useEffect ( ( ) => {
41- if ( ! isLoading && pageInfo ?. nextCursor ) {
72+ if ( ! isLoading && nextCursor ) {
4273 // We add nextCursor when available
43- mapPageToNextCursor . current [ paginationModel . page ] = pageInfo ?. nextCursor ;
74+ mapPageToNextCursor . current [ paginationModel . page ] = nextCursor ;
4475 }
45- } , [ paginationModel . page , isLoading , pageInfo ?. nextCursor ] ) ;
76+ } , [ paginationModel . page , isLoading , nextCursor ] ) ;
4677
4778 // Some API clients return undefined while loading
4879 // Following lines are here to prevent `rowCountState` from being undefined during the loading
49- const [ rowCountState , setRowCountState ] = React . useState (
50- pageInfo ?. totalRowCount || 0 ,
51- ) ;
80+ const [ rowCountState , setRowCountState ] = React . useState ( totalRowCount || 0 ) ;
5281 React . useEffect ( ( ) => {
53- setRowCountState ( ( prevRowCountState ) =>
54- pageInfo ?. totalRowCount !== undefined
55- ? pageInfo ?. totalRowCount
56- : prevRowCountState ,
57- ) ;
58- } , [ pageInfo ?. totalRowCount , setRowCountState ] ) ;
82+ if ( rowCountType === 'known' ) {
83+ setRowCountState ( ( prevRowCountState ) =>
84+ totalRowCount !== undefined ? totalRowCount : prevRowCountState ,
85+ ) ;
86+ }
87+ if (
88+ ( rowCountType === 'unknown' || rowCountType === 'estimated' ) &&
89+ paginationMeta ?. hasNextPage !== false
90+ ) {
91+ setRowCountState ( - 1 ) ;
92+ }
93+ } , [ paginationMeta ?. hasNextPage , rowCountType , totalRowCount ] ) ;
94+
95+ const prevEstimatedRowCount = React . useRef < number | undefined > ( undefined ) ;
96+ const estimatedRowCount = React . useMemo ( ( ) => {
97+ if ( rowCountType === 'estimated' ) {
98+ if ( totalRowCount !== undefined ) {
99+ if ( prevEstimatedRowCount . current === undefined ) {
100+ prevEstimatedRowCount . current = totalRowCount / 2 ;
101+ }
102+ return totalRowCount / 2 ;
103+ }
104+ return prevEstimatedRowCount . current ;
105+ }
106+ return undefined ;
107+ } , [ rowCountType , totalRowCount ] ) ;
59108
60109 return (
61- < div style = { { height : 400 , width : '100%' } } >
62- < DataGrid
63- rows = { rows }
64- { ...data }
65- pageSizeOptions = { [ PAGE_SIZE ] }
66- rowCount = { rowCountState }
67- paginationMode = "server"
68- onPaginationModelChange = { handlePaginationModelChange }
69- paginationModel = { paginationModel }
70- loading = { isLoading }
71- />
110+ < div style = { { width : '100%' } } >
111+ < FormControl >
112+ < FormLabel id = "demo-cursor-pagination-buttons-group-label" >
113+ Row count
114+ </ FormLabel >
115+ < RadioGroup
116+ row
117+ aria-labelledby = "demo-cursor-pagination-buttons-group-label"
118+ name = "cursor-pagination-buttons-group"
119+ value = { rowCountType }
120+ onChange = { ( e ) => setRowCountType ( e . target . value as RowCountType ) }
121+ >
122+ < FormControlLabel value = "known" control = { < Radio /> } label = "Known" />
123+ < FormControlLabel value = "unknown" control = { < Radio /> } label = "Unknown" />
124+ < FormControlLabel
125+ value = "estimated"
126+ control = { < Radio /> }
127+ label = "Estimated"
128+ />
129+ </ RadioGroup >
130+ </ FormControl >
131+ < div style = { { height : 400 } } >
132+ < DataGrid
133+ rows = { rows }
134+ { ...data }
135+ pageSizeOptions = { [ PAGE_SIZE ] }
136+ rowCount = { rowCountState }
137+ onRowCountChange = { ( newRowCount ) => setRowCountState ( newRowCount ) }
138+ estimatedRowCount = { estimatedRowCount }
139+ paginationMeta = { paginationMeta }
140+ paginationMode = "server"
141+ onPaginationModelChange = { handlePaginationModelChange }
142+ paginationModel = { paginationModel }
143+ loading = { isLoading }
144+ />
145+ </ div >
72146 </ div >
73147 ) ;
74148}
0 commit comments