Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Pagination refactoring #100

Merged
merged 18 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/demo-app/src/app/demos/grid/real-data-grid.demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ export const RealDataGridDemo: React.FC<{ toggleTheme: () => void; themeId: stri

const newPagination: Partial<GridOptions> = {
pagination: settings.pagesize !== -1,
paginationAutoPageSize: settings.pagesize === 0,
paginationPageSize: settings.pagesize > 0 ? settings.pagesize : undefined,
autoPageSize: settings.pagesize === 0,
pageSize: settings.pagesize > 0 ? settings.pagesize : undefined,
};

setPagination((p) => {
if (
p.pagination === newPagination.pagination &&
p.paginationAutoPageSize === newPagination.paginationAutoPageSize &&
p.paginationPageSize === newPagination.paginationPageSize
p.autoPageSize === newPagination.autoPageSize &&
p.pageSize === newPagination.pageSize
) {
return p;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/grid/data-grid/src/data-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export const DataGrid: React.FC<DataGridProps> = React.memo(function DataGrid(
props: DataGridProps,
) {
const validateOptions = React.useCallback((options: DataGridOptionsProp) => {
if (options && options.paginationPageSize && options.paginationPageSize > MAX_PAGE_SIZE) {
if (options && options.pageSize && options.pageSize > MAX_PAGE_SIZE) {
throw new Error(
`Material-UI: Option 'paginationPageSize' cannot be above ${MAX_PAGE_SIZE}. Use the @material-ui/x-grid to unlock this feature`,
`Material-UI: Option 'pageSize' cannot be above ${MAX_PAGE_SIZE}. Use the @material-ui/x-grid to unlock this feature`,
);
}
return options;
Expand Down
12 changes: 8 additions & 4 deletions packages/grid/x-grid-modules/src/gridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ export const GridComponent: React.FC<GridComponentProps> = React.memo(

React.useEffect(() => {
setInternalOptions((previousState) => {
if (previousState.paginationPageSize !== paginationProps.pageSize) {
return { ...previousState, paginationPageSize: paginationProps.pageSize };
if (previousState.pageSize !== paginationProps.pageSize) {
return { ...previousState, pageSize: paginationProps.pageSize };
}
return previousState;
});
Expand Down Expand Up @@ -215,11 +215,15 @@ export const GridComponent: React.FC<GridComponentProps> = React.memo(
pageSize={paginationProps.pageSize}
rowCount={paginationProps.rowCount}
setPageSize={paginationProps.setPageSize}
rowsPerPageOptions={internalOptions.paginationRowsPerPageOptions}
rowsPerPageOptions={internalOptions.rowsPerPageOptions}
/>
))
}
rowCount={internalRows.length}
rowCount={
internalOptions.rowCount == null
? internalRows.length
: internalOptions.rowCount
}
options={internalOptions}
/>
)}
Expand Down
69 changes: 51 additions & 18 deletions packages/grid/x-grid-modules/src/hooks/features/usePagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { InternalColumns } from '../../models/colDef/colDef';
import { GridOptions } from '../../models/gridOptions';
import { PaginationApi } from '../../models/api/paginationApi';
import { ApiRef } from '../../models/api';
import { FeatureMode } from '../../models/featureMode';

export interface PaginationProps {
page: number;
Expand Down Expand Up @@ -54,10 +55,14 @@ export const usePagination = (
const logger = useLogger('usePagination');

const initialState: PaginationState = {
pageSize: options.paginationPageSize || 0,
rowCount: rows.length,
page: 1,
pageCount: getPageCount(options.paginationPageSize, rows.length),
paginationMode: options.paginationMode!,
pageSize: options.pageSize || 0,
rowCount: options.rowCount == null ? rows.length : options.rowCount,
page: options.page || 1,
pageCount: getPageCount(
options.pageSize,
options.rowCount == null ? rows.length : options.rowCount,
),
};
const stateRef = useRef(initialState);
const [state, dispatch] = useReducer(paginationReducer, initialState);
Expand All @@ -74,7 +79,11 @@ export const usePagination = (
const setPage = useCallback(
(page: number) => {
if (apiRef && apiRef.current) {
apiRef.current!.renderPage(page);
page = stateRef.current.pageCount >= page ? page : stateRef.current.pageCount;
apiRef.current!.renderPage(
stateRef.current.paginationMode === FeatureMode.client ? page : 1,
);

const params: PageChangedParams = {
...stateRef.current,
page,
Expand Down Expand Up @@ -149,41 +158,65 @@ export const usePagination = (
}, [state]);

useEffect(() => {
if (rows.length !== state.rowCount) {
if (apiRef.current?.isInitialised) {
apiRef.current!.emit(PAGE_CHANGED_EVENT, stateRef.current);
}
}, [apiRef, stateRef, apiRef.current?.isInitialised]);

useEffect(() => {
oliviertassinari marked this conversation as resolved.
Show resolved Hide resolved
updateState({ paginationMode: options.paginationMode! });
}, [options.paginationMode, updateState]);

useEffect(() => {
setPage(options.page != null ? options.page : 1);
}, [options.page, setPage]);

useEffect(() => {
const rowCount = options.rowCount == null ? rows.length : options.rowCount;
if (rowCount !== state.rowCount) {
logger.info(`Options or rows changed, recalculating pageCount and rowCount`);
const newPageCount = getPageCount(state.pageSize, rows.length);
const newPageCount = getPageCount(state.pageSize, rowCount);

updateState({ pageCount: newPageCount, rowCount: rows.length });
updateState({ pageCount: newPageCount, rowCount });
if (state.page > newPageCount) {
setPage(newPageCount);
}
}
}, [rows.length, logger, updateState, state.rowCount, state.pageSize, setPage, state.page]);
}, [
rows.length,
options.rowCount,
logger,
updateState,
state.rowCount,
state.pageSize,
setPage,
state.page,
]);

useEffect(() => {
if (
!options.paginationAutoPageSize &&
options.paginationPageSize &&
options.paginationPageSize !== stateRef.current.pageSize
!options.autoPageSize &&
options.pageSize &&
options.pageSize !== stateRef.current.pageSize
) {
setPageSize(options.paginationPageSize);
setPageSize(options.pageSize);
}
}, [options.paginationAutoPageSize, options.paginationPageSize, logger, setPageSize]);
}, [options.autoPageSize, options.pageSize, logger, setPageSize]);

useEffect(() => {
if (options.paginationAutoPageSize && columns.visible.length > 0) {
if (options.autoPageSize && columns.visible.length > 0) {
resetAutopageSize();
}
}, [options.paginationAutoPageSize, resetAutopageSize, columns.visible.length]);
}, [options.autoPageSize, resetAutopageSize, columns.visible.length]);

useApiEventHandler(apiRef, PAGE_CHANGED_EVENT, options.onPageChanged);
useApiEventHandler(apiRef, PAGESIZE_CHANGED_EVENT, options.onPageSizeChanged);

const onResize = useCallback(() => {
if (options.paginationAutoPageSize) {
if (options.autoPageSize) {
resetAutopageSize();
}
}, [options.paginationAutoPageSize, resetAutopageSize]);
}, [options.autoPageSize, resetAutopageSize]);

useApiEventHandler(apiRef, RESIZE, onResize);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const useContainerProps = (windowRef: React.RefObject<HTMLDivElement>): R

const rowHeight = options.rowHeight;
const hasScrollY =
options.paginationAutoPageSize || options.autoHeight
options.autoPageSize || options.autoHeight
? false
: windowSizesRef.current.height < rowsCount * rowHeight;
const hasScrollX = columnsTotalWidth > windowSizesRef.current.width;
Expand All @@ -50,17 +50,15 @@ export const useContainerProps = (windowRef: React.RefObject<HTMLDivElement>): R
// We multiply by 2 for virtualization
// TODO allow buffer with fixed nb rows
const rzPageSize = viewportPageSize * 2;
const viewportMaxPage = options.paginationAutoPageSize
? 1
: Math.ceil(rowsCount / viewportPageSize);
const viewportMaxPage = options.autoPageSize ? 1 : Math.ceil(rowsCount / viewportPageSize);

logger.debug(
`viewportPageSize: ${viewportPageSize}, rzPageSize: ${rzPageSize}, viewportMaxPage: ${viewportMaxPage}`,
);
const renderingZoneHeight = rzPageSize * rowHeight + rowHeight + scrollBarSize.x;
const dataContainerWidth = columnsTotalWidth - scrollBarSize.y;
let totalHeight =
(options.paginationAutoPageSize ? 1 : rowsCount / viewportPageSize) * viewportSize.height +
(options.autoPageSize ? 1 : rowsCount / viewportPageSize) * viewportSize.height +
(hasScrollY ? scrollBarSize.x : 0);

if (options.autoHeight) {
Expand Down
6 changes: 2 additions & 4 deletions packages/grid/x-grid-modules/src/hooks/root/useKeyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ export const useKeyboard = (options: GridOptions, initialised: boolean, apiRef:
const currentRowIndex = Number(getDataFromElem(cellEl, 'rowindex'));
const autoPageSize = apiRef.current!.getContainerPropsState()!.viewportPageSize;
const pageSize =
options.pagination && options.paginationPageSize != null
? options.paginationPageSize
: autoPageSize;
options.pagination && options.pageSize != null ? options.pageSize : autoPageSize;
const rowCount = options.pagination ? pageSize : apiRef.current!.getRowsCount();
const colCount = apiRef.current!.getVisibleColumns().length;

Expand Down Expand Up @@ -120,7 +118,7 @@ export const useKeyboard = (options: GridOptions, initialised: boolean, apiRef:

return nextCellIndexes;
},
[apiRef, options.pagination, options.paginationPageSize],
[apiRef, options.pagination, options.pageSize],
);

const selectActiveRow = React.useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ export const useVirtualRows = (
}
const containerProps = containerPropsRef.current!;
let minRowIdx = 0;
if (optionsRef.current.pagination && optionsRef.current.paginationPageSize != null) {
if (optionsRef.current.pagination && optionsRef.current.pageSize != null) {
minRowIdx =
optionsRef.current.paginationPageSize *
optionsRef.current.pageSize *
(paginationCurrentPage.current - 1 > 0 ? paginationCurrentPage.current - 1 : 0);
}

Expand Down Expand Up @@ -96,7 +96,7 @@ export const useVirtualRows = (
...renderedRow,
...{
paginationCurrentPage: paginationCurrentPage.current,
paginationPageSize: optionsRef.current.paginationPageSize,
pageSize: optionsRef.current.pageSize,
},
};
logger.debug(':: getRenderCtxState - returning state ', newRenderCtx);
Expand Down Expand Up @@ -174,8 +174,8 @@ export const useVirtualRows = (
const totalRowsCount = apiRef?.current?.getRowsCount() || 0; // we ensure we call with latest length
const currentPage = paginationCurrentPage.current;
let pageRowCount =
optionsRef.current.pagination && optionsRef.current.paginationPageSize
? optionsRef.current.paginationPageSize
optionsRef.current.pagination && optionsRef.current.pageSize
? optionsRef.current.pageSize
: null;

pageRowCount =
Expand All @@ -190,7 +190,7 @@ export const useVirtualRows = (
columnTotalWidthRef.current,
rowsCount.current,
);
if (optionsRef.current.paginationAutoPageSize && containerPropsRef.current) {
if (optionsRef.current.autoPageSize && containerPropsRef.current) {
rowsCount.current = containerPropsRef.current.viewportPageSize;
}
updateViewport();
Expand Down
4 changes: 4 additions & 0 deletions packages/grid/x-grid-modules/src/models/featureMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum FeatureMode {
client = 'client',
server = 'server',
}
29 changes: 23 additions & 6 deletions packages/grid/x-grid-modules/src/models/gridOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RowSelectedParams } from './params/rowSelectedParams';
import { SelectionChangedParams } from './params/selectionChangedParams';
import { PageChangedParams } from './params/pageChangedParams';
import { ColumnTypesRecord, DEFAULT_COLUMN_TYPES } from './colDef';
import { FeatureMode } from './featureMode';

/**
* Set of icons used in the grid component UI.
Expand Down Expand Up @@ -98,17 +99,32 @@ export interface GridOptions {
* Set the number of rows in one page.
* @default 100
*/
paginationPageSize?: number;
pageSize?: number;
/**
* Auto-scale the pageSize with the container size to the max number of rows to avoid rendering a vertical scroll bar.
* @default false
*/
paginationAutoPageSize?: boolean;
autoPageSize?: boolean;
/**
* Select the paginationPageSize dynamically using the component UI.
* Select the pageSize dynamically using the component UI.
* @default [25, 50, 100]
*/
paginationRowsPerPageOptions?: number[];
rowsPerPageOptions?: number[];
/**
* Pagination can be processed on the server or client-side.
* Set it to FeatureMode.client or `client` if you would like to handle the pagination on the client-side.
* Set it to FeatureMode.server or `server` if you would like to handle the pagination on the server-side.
*/
paginationMode?: FeatureMode;
/**
* Set the total number of rows, if it is different than the length of the value `rows` prop.
*/
rowCount?: number;
/**
* Set the current page.
* @default 1
*/
page?: number;
/**
* Toggle footer component visibility.
* @default false
Expand Down Expand Up @@ -213,8 +229,9 @@ export const DEFAULT_GRID_OPTIONS: GridOptions = {
columnBuffer: 2,
enableMultipleSelection: true,
enableMultipleColumnsSorting: true,
paginationRowsPerPageOptions: [25, 50, 100],
paginationPageSize: 100,
rowsPerPageOptions: [25, 50, 100],
pageSize: 100,
paginationMode: FeatureMode.client,
extendRowFullWidth: true,
sortingOrder: ['asc', 'desc', null],
columnTypes: DEFAULT_COLUMN_TYPES,
Expand Down
1 change: 1 addition & 0 deletions packages/grid/x-grid-modules/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './colDef';
export * from './containerProps';
export * from './elementSize';
export * from './featureMode';
export * from './gridOptions';
export * from './rootContainerRef';
export * from './renderContextProps';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FeatureMode } from '../featureMode';

/**
* Object passed as parameter of the page changed event handler.
*/
Expand All @@ -18,4 +20,5 @@ export interface PageChangedParams {
* The total number of rows
*/
rowCount: number;
paginationMode: FeatureMode;
}
4 changes: 2 additions & 2 deletions packages/grid/x-grid-modules/src/models/renderContextProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export interface RenderPaginationProps {
*/
paginationCurrentPage?: number;
/**
* The current page size if pagination is enabled
* The current page size if pagination is enabled.
*/
paginationPageSize?: number;
pageSize?: number;
}

/**
Expand Down
9 changes: 7 additions & 2 deletions packages/storybook/src/documentation/pages/api.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { XGrid } from '@material-ui/x-grid';

## How to use ApiRef?

The `ApiRef` allows you to manipulate the grid outside the React component context. This can be very handy in a streaming api to update rows with changes from the server.
The `ApiRef` allows you to manipulate the grid outside the React component scope.
To enable ApiRef, you need to use the `useApiRef` hook and pass the ref to the component prop as below.

```tsx
Expand All @@ -17,7 +17,12 @@ return <XGrid rows={rows} columns={columns} apiRef={apiRef} />

```

Generated?
## Use cases

If you would like to manipulate the grid outside the component rendering the XGrid, for example if you are building some custom filters.
You could pass the apiRef using the context or as a prop.

This can also be very handy in a streaming api to update rows with changes from the server as we have exposed in our Rows section [here]().

## GridAPI

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function AutoPageSizeDemo() {
<XGrid
rows={rows}
columns={columns}
options={{ pagination: true, paginationAutoPageSize: true }}
options={{ pagination: true, autoPageSize: true }}
className="demo"
/>
</div>
Expand Down
Loading