Skip to content

Commit

Permalink
allow to disable virtualization
Browse files Browse the repository at this point in the history
  • Loading branch information
m4theushw committed Aug 12, 2021
1 parent 624352e commit fe60f82
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 48 deletions.
1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/data-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { DataGrid } from '@material-ui/data-grid';
| <span class="prop-name">disableDensitySelector</span> | <span class="prop-type">boolean</span> | false | If `true`, the density selector is disabled. |
| <span class="prop-name">disableExtendRowFullWidth</span> | <span class="prop-type">boolean</span> | false | If `true`, rows will not be extended to fill the full width of the grid container. |
| <span class="prop-name">disableSelectionOnClick</span> | <span class="prop-type">boolean</span> | false | If `true`, the selection on click on a row or cell is disabled. |
| <span class="prop-name">disableVirtualization</span> | <span class="prop-type">boolean</span> | false | If `true`, the virtualization is disabled. |
| <span class="prop-name">error</span> | <span class="prop-type">any</span> | | An error that will turn the grid into its error state and display the error component. |
| <span class="prop-name">editRowsModel</span> | <span class="prop-type">GridEditRowsModel</span> | undefined | Set the edit rows model of the grid. |
| <span class="prop-name">filterMode</span> | <span class="prop-type">GridFeatureMode</span> | 'client' | Filtering can be processed on the server or client-side. Set it to `server` if you would like to handle filtering on the server-side. |
Expand Down
21 changes: 0 additions & 21 deletions docs/pages/api-docs/data-grid/grid-virtualization-api.json

This file was deleted.

1 change: 1 addition & 0 deletions docs/pages/api-docs/data-grid/x-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { XGrid } from '@material-ui/x-grid';
| <span class="prop-name">disableMultipleColumnsSorting</span> | <span class="prop-type">boolean</span> | false | If `true`, sorting with multiple columns is disabled. |
| <span class="prop-name">disableMultipleSelection</span> | <span class="prop-type">boolean</span> | false | If `true`, multiple selection using the CTRL or CMD key is disabled. |
| <span class="prop-name">disableSelectionOnClick</span> | <span class="prop-type">boolean</span> | false | If `true`, the selection on click on a row or cell is disabled. |
| <span class="prop-name">disableVirtualization</span> | <span class="prop-type">boolean</span> | false | If `true`, the virtualization is disabled. |
| <span class="prop-name">error</span> | <span class="prop-type">any</span> | | An error that will turn the grid into its error state and display the error component. |
| <span class="prop-name">editRowsModel</span> | <span class="prop-type">GridEditRowsModel</span> | undefined | Set the edit rows model of the grid. |
| <span class="prop-name">filterMode</span> | <span class="prop-type">GridFeatureMode</span> | 'client' | Filtering can be processed on the server or client-side. Set it to `server` if you would like to handle filtering on the server-side. |
Expand Down
1 change: 0 additions & 1 deletion docs/scripts/buildApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ function run(argv: { outputDirectory?: string }) {
'GridFilterApi',
'GridCsvExportApi',
'GridExportCsvOptions',
'GridVirtualizationApi',
'GridEvents',
];

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ By default, 2 columns are rendered outside of the viewport. You can change this

You can disable column virtualization by setting the column buffer to a higher number than the number of rendered columns, e.g. with `columnBuffer={columns.length}` or `columnBuffer={Number.MAX_SAFE_INTEGER}`.

## apiRef [<span class="pro"></span>](https://material-ui.com/store/items/material-ui-pro/)
## Disable virtualization

{{"demo": "pages/components/data-grid/virtualization/VirtualizationApiNoSnap.js", "bg": "inline", "hideToolbar": true}}
The virtualization can be disabled entirely using the `disableVirtualization` prop.

```tsx
<DataGrid {...data} disableVirtualization />
```

## API

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as React from 'react';
import { GridComponentProps } from '../../../GridComponentProps';
import { GridApiRef } from '../../../models/api/gridApiRef';
import { useNativeEventListener } from '../../root/useNativeEventListener';
import { useGridScrollFn } from '../../utils/useGridScrollFn';
import { visibleGridColumnsSelector } from '../columns/gridColumnsSelector';
import { useGridSelector } from '../core';
import { useGridState } from '../core/useGridState';
import { gridPaginationSelector } from '../pagination/gridPaginationSelector';

export const useGridNoVirtualization = (
apiRef: GridApiRef,
props: Pick<GridComponentProps, 'disableVirtualization' | 'pagination' | 'paginationMode'>,
): void => {
const windowRef = apiRef.current.windowRef;
const columnsHeaderRef = apiRef.current.columnHeadersElementRef;
const renderingZoneRef = apiRef.current.renderingZoneRef;
const [gridState, setGridState, forceUpdate] = useGridState(apiRef);
const [scrollTo] = useGridScrollFn(renderingZoneRef!, columnsHeaderRef!);
const paginationState = useGridSelector(apiRef, gridPaginationSelector);
const visibleColumns = useGridSelector(apiRef, visibleGridColumnsSelector);

const syncState = React.useCallback(() => {
if (!gridState.containerSizes || !windowRef?.current) {
return;
}

let firstRowIdx = 0;
const { page, pageSize } = paginationState;
if (props.pagination && pageSize != null && props.paginationMode === 'client') {
firstRowIdx = pageSize * page;
}
const lastRowIdx = firstRowIdx + gridState.containerSizes.virtualRowsCount;
const lastColIdx = visibleColumns.length > 0 ? visibleColumns.length - 1 : 0;
const renderContext = { firstRowIdx, lastRowIdx, firstColIdx: 0, lastColIdx };

const scrollParams = {
top: windowRef.current!.scrollTop,
left: windowRef.current!.scrollLeft,
};

setGridState((state) => ({
...state,
rendering: {
...state.rendering,
virtualPage: 0,
renderContext,
realScroll: scrollParams,
renderingZoneScroll: scrollParams,
},
}));
forceUpdate();
}, [
gridState.containerSizes,
paginationState,
props.pagination,
props.paginationMode,
setGridState,
forceUpdate,
visibleColumns.length,
windowRef,
]);

React.useEffect(() => {
if (!props.disableVirtualization) {
return;
}
syncState();
}, [props.disableVirtualization, syncState]);

const handleScroll = React.useCallback(() => {
if (!props.disableVirtualization || !windowRef?.current) {
return;
}
const { scrollLeft, scrollTop } = windowRef.current;
scrollTo({ top: scrollTop, left: scrollLeft });
syncState();
}, [props.disableVirtualization, scrollTo, windowRef, syncState]);

useNativeEventListener(apiRef, windowRef!, 'scroll', handleScroll, { passive: true });
};
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ export const useGridVirtualization = (apiRef: GridApiRef): void => {

const updateViewport = React.useCallback(
(forceReRender = false) => {
if (options.disableVirtualization) {
return;
}

const lastState = apiRef.current.getState();
const containerProps = lastState.containerSizes;
if (!windowRef || !windowRef.current || !containerProps) {
Expand Down Expand Up @@ -290,6 +294,7 @@ export const useGridVirtualization = (apiRef: GridApiRef): void => {
setRenderingState,
updateRenderedCols,
windowRef,
options.disableVirtualization,
],
);

Expand All @@ -306,6 +311,10 @@ export const useGridVirtualization = (apiRef: GridApiRef): void => {

const scrollingTimeout = React.useRef<any>(null);
const handleScroll = React.useCallback(() => {
if (options.disableVirtualization) {
return;
}

// On iOS the inertia scrolling allows to return negative values.
if (windowRef.current!.scrollLeft < 0 || windowRef.current!.scrollTop < 0) return;

Expand All @@ -322,7 +331,7 @@ export const useGridVirtualization = (apiRef: GridApiRef): void => {
if (apiRef.current.updateViewport) {
apiRef.current.updateViewport();
}
}, [windowRef, apiRef, setGridState, forceUpdate]);
}, [options.disableVirtualization, windowRef, apiRef, setGridState, forceUpdate]);

const getContainerPropsState = React.useCallback(
() => gridState.containerSizes,
Expand All @@ -334,6 +343,10 @@ export const useGridVirtualization = (apiRef: GridApiRef): void => {
}, [gridState.rendering.renderContext]);

useEnhancedEffect(() => {
if (options.disableVirtualization) {
return;
}

if (renderingZoneRef && renderingZoneRef.current) {
logger.debug('applying scrollTop ', gridState.rendering.renderingZoneScroll.top);
scrollTo(gridState.rendering.renderingZoneScroll);
Expand Down
12 changes: 10 additions & 2 deletions packages/grid/_modules_/grid/hooks/root/useGridContainerProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const useGridContainerProps = (apiRef: GridApiRef) => {
const requiredSize = rowsCount * rowHeight;
const diff = requiredSize - windowSizesRef.current.height;
// we activate virtualization when we have more than 2 rows outside the viewport
const isVirtualized = diff > rowHeight * 2;
const isVirtualized = diff > rowHeight * 2 && !options.disableVirtualization;

if (options.autoPageSize || options.autoHeight || !isVirtualized) {
const viewportFitHeightSize = Math.floor(viewportSizes.height / rowHeight);
Expand Down Expand Up @@ -212,7 +212,15 @@ export const useGridContainerProps = (apiRef: GridApiRef) => {
logger.debug('virtualized container props', indexes);
return indexes;
},
[windowRef, columnsTotalWidth, rowHeight, options.autoPageSize, options.autoHeight, logger],
[
windowRef,
columnsTotalWidth,
rowHeight,
options.disableVirtualization,
options.autoPageSize,
options.autoHeight,
logger,
],
);

const updateStateIfChanged = React.useCallback(
Expand Down
5 changes: 5 additions & 0 deletions packages/grid/_modules_/grid/models/gridOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ export interface GridOptions {
* @default false
*/
disableSelectionOnClick?: boolean;
/**
* If `true`, the virtualization is disabled.
* @default false
*/
disableVirtualization?: boolean;
/**
* Set the edit rows model of the grid.
*/
Expand Down
23 changes: 9 additions & 14 deletions packages/grid/data-grid/src/tests/keyboard.DataGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ describe('<DataGrid /> - Keyboard', () => {
expect(handleKeyDown.returnValues).to.deep.equal([true]);
});

const KeyboardTest = (props: { nbRows?: number; checkboxSelection?: boolean }) => {
const KeyboardTest = (props: {
nbRows?: number;
checkboxSelection?: boolean;
disableVirtualization?: boolean;
}) => {
const data = useData(props.nbRows || 100, 20);
const transformColSizes = (columns: GridColumns) =>
columns.map((column) => ({ ...column, width: 60 }));
Expand All @@ -140,6 +144,7 @@ describe('<DataGrid /> - Keyboard', () => {
rows={data.rows}
columns={transformColSizes(data.columns)}
checkboxSelection={props.checkboxSelection}
disableVirtualization={props.disableVirtualization}
/>
</div>
);
Expand Down Expand Up @@ -191,16 +196,11 @@ describe('<DataGrid /> - Keyboard', () => {
});

it('Space only should go to the bottom of the page', function test() {
if (isJSDOM) {
// Need layouting for row virtualization
this.skip();
}

render(<KeyboardTest />);
render(<KeyboardTest disableVirtualization />);
getCell(0, 0).focus();
expect(getActiveCell()).to.equal('0-0');
fireEvent.keyDown(document.activeElement!, { key: ' ' });
expect(getActiveCell()).to.equal('4-0');
expect(getActiveCell()).to.equal('99-0');
});

it('Space only should go to the bottom of the page even with small number of rows', () => {
Expand All @@ -212,12 +212,7 @@ describe('<DataGrid /> - Keyboard', () => {
});

it('Home / End navigation', async function test() {
if (isJSDOM) {
// Need layouting for column virtualization
this.skip();
}

render(<KeyboardTest />);
render(<KeyboardTest disableVirtualization />);
getCell(1, 1).focus();
expect(getActiveCell()).to.equal('1-1');
fireEvent.keyDown(document.activeElement!, { key: 'Home' });
Expand Down
2 changes: 2 additions & 0 deletions packages/grid/data-grid/src/useDataGridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useGridSelection } from '../../_modules_/grid/hooks/features/selection/
import { useGridSorting } from '../../_modules_/grid/hooks/features/sorting/useGridSorting';
import { useGridComponents } from '../../_modules_/grid/hooks/features/useGridComponents';
import { useGridVirtualization } from '../../_modules_/grid/hooks/features/virtualization/useGridVirtualization';
import { useGridNoVirtualization } from '../../_modules_/grid/hooks/features/virtualization/useGridNoVirtualization';
import { useGridScroll } from '../../_modules_/grid/hooks/features/scroll/useGridScroll';
import { useApi } from '../../_modules_/grid/hooks/root/useApi';
import { useEvents } from '../../_modules_/grid/hooks/root/useEvents';
Expand Down Expand Up @@ -62,6 +63,7 @@ export const useDataGridComponent = (apiRef: GridApiRef, props: GridComponentPro
useGridContainerProps(apiRef);
useGridDensity(apiRef, props);
useGridScroll(apiRef, props);
useGridNoVirtualization(apiRef, props);
useGridVirtualization(apiRef);
useGridColumnResize(apiRef, props);
useGridPageSize(apiRef, props);
Expand Down
33 changes: 33 additions & 0 deletions packages/grid/x-grid/src/tests/rows.XGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,39 @@ describe('<XGrid /> - Rows', () => {
});
});

describe('no virtualization', () => {
let apiRef: GridApiRef;

const TestCase = (props: Partial<XGridProps> & { nbRows?: number; nbCols?: number }) => {
apiRef = useGridApiRef();
const data = useData(props.nbRows || 100, props.nbCols || 10);
return (
<div style={{ width: 300, height: 300 }}>
<XGrid
apiRef={apiRef}
columns={data.columns}
rows={data.rows}
disableVirtualization
{...props}
/>
</div>
);
};

it('should allow to disable virtualization', () => {
render(<TestCase nbRows={100} nbCols={10} />);
expect(document.querySelectorAll('[role="row"][data-rowindex]')).to.have.length(100);
expect(document.querySelectorAll('[role="cell"]')).to.have.length(100 * 10);
});

it('should render the correct rows when changing pages', () => {
render(<TestCase nbRows={150} nbCols={10} pagination />);
expect(document.querySelectorAll('[role="row"][data-rowindex]')).to.have.length(100);
apiRef.current.setPage(1);
expect(document.querySelectorAll('[role="row"][data-rowindex]')).to.have.length(50);
});
});

describe('Cell focus', () => {
let apiRef: GridApiRef;

Expand Down
2 changes: 2 additions & 0 deletions packages/grid/x-grid/src/useXGridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useGridSelection } from '../../_modules_/grid/hooks/features/selection/
import { useGridSorting } from '../../_modules_/grid/hooks/features/sorting/useGridSorting';
import { useGridComponents } from '../../_modules_/grid/hooks/features/useGridComponents';
import { useGridVirtualization } from '../../_modules_/grid/hooks/features/virtualization/useGridVirtualization';
import { useGridNoVirtualization } from '../../_modules_/grid/hooks/features/virtualization/useGridNoVirtualization';
import { useGridScroll } from '../../_modules_/grid/hooks/features/scroll/useGridScroll';
import { useApi } from '../../_modules_/grid/hooks/root/useApi';
import { useEvents } from '../../_modules_/grid/hooks/root/useEvents';
Expand Down Expand Up @@ -63,6 +64,7 @@ export const useXGridComponent = (apiRef: GridApiRef, props: GridComponentProps)
useGridContainerProps(apiRef);
useGridDensity(apiRef, props);
useGridScroll(apiRef, props);
useGridNoVirtualization(apiRef, props);
useGridVirtualization(apiRef);
useGridColumnReorder(apiRef, props);
useGridColumnResize(apiRef, props);
Expand Down
15 changes: 15 additions & 0 deletions packages/storybook/src/stories/grid-rows.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,21 @@ export function SwitchVirtualization() {
</div>
);
}

export function DisableVirtualization() {
const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 200,
maxColumns: 4,
});

return (
<div style={{ width: '100%', height: '100%' }}>
<XGrid rows={data.rows} columns={data.columns} pagination disableVirtualization />
</div>
);
}

export function DeferRendering() {
const [deferRows, setRows] = React.useState<any>([]);
const [deferColumns] = React.useState([{ field: 'id', headerName: 'Id', width: 100 }]);
Expand Down

0 comments on commit fe60f82

Please sign in to comment.