Skip to content

Commit

Permalink
[DataGrid] Refactor containerSizes in smaller state (mui#544)
Browse files Browse the repository at this point in the history
* refactoring containerSizes in smaller state

* prettier

* fix column resize

* refactor updateViewport

* fix tests

* fix review

* fix resize warning

* prettier

* only needed for simpler tests in JSDOM

* upgrade Safari as 13 is more reliable

* Update packages/grid/_modules_/grid/models/api/virtualizationApi.ts

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>
  • Loading branch information
dtassone and oliviertassinari committed Nov 9, 2020
1 parent da1be9c commit a92a543
Show file tree
Hide file tree
Showing 15 changed files with 403 additions and 277 deletions.
2 changes: 1 addition & 1 deletion packages/grid/_modules_/grid/GridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const GridComponent = React.forwardRef<HTMLDivElement, GridComponentProps
<ColumnsHeader
ref={columnsHeaderRef}
columns={gridState.columns.visible || []}
hasScrollX={!!gridState.containerSizes?.hasScrollX}
hasScrollX={!!gridState.scrollBar.hasScrollX}
separatorProps={separatorProps}
renderCtx={renderCtx}
/>
Expand Down
15 changes: 11 additions & 4 deletions packages/grid/_modules_/grid/components/viewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { StickyContainer } from './sticky-container';
type ViewportType = React.ForwardRefExoticComponent<React.RefAttributes<HTMLDivElement>>;

export const containerSizesSelector = (state: GridState) => state.containerSizes;
export const viewportSizesSelector = (state: GridState) => state.viewportSizes;
export const scrollBarSizeSelector = (state: GridState) => state.scrollBar;

export const Viewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(
(props, renderingZoneRef) => {
Expand All @@ -28,6 +30,8 @@ export const Viewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(
const rows = useGridSelector(apiRef, sortedRowsSelector);
const options = useGridSelector(apiRef, optionsSelector);
const containerSizes = useGridSelector(apiRef, containerSizesSelector);
const viewportSizes = useGridSelector(apiRef, viewportSizesSelector);
const scrollBarState = useGridSelector(apiRef, scrollBarSizeSelector);
const columns = useGridSelector(apiRef, columnsSelector);
const cellFocus = useGridSelector(apiRef, keyboardCellSelector);
const selectionState = useGridSelector(apiRef, selectionStateSelector);
Expand All @@ -49,8 +53,8 @@ export const Viewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(
row={r}
firstColIdx={renderCtx.firstColIdx}
lastColIdx={renderCtx.lastColIdx}
hasScroll={{ y: containerSizes!.hasScrollY, x: containerSizes!.hasScrollX }}
scrollSize={containerSizes!.scrollBarSize}
hasScroll={{ y: scrollBarState!.hasScrollY, x: scrollBarState.hasScrollX }}
scrollSize={options.scrollbarSize}
showCellRightBorder={!!options.showCellRightBorder}
extendRowFullWidth={!options.disableExtendRowFullWidth}
rowIndex={renderCtx.firstRowIdx + idx}
Expand All @@ -64,8 +68,11 @@ export const Viewport: ViewportType = React.forwardRef<HTMLDivElement, {}>(

logger.debug('Rendering ViewPort');
return (
<StickyContainer {...containerSizes!.viewportSize}>
<RenderingZone ref={renderingZoneRef} {...containerSizes!.renderingZone}>
<StickyContainer {...viewportSizes}>
<RenderingZone
ref={renderingZoneRef}
{...(containerSizes?.renderingZone || { width: 0, height: 0 })}
>
{getRowsElements()}
</RenderingZone>
</StickyContainer>
Expand Down
64 changes: 43 additions & 21 deletions packages/grid/_modules_/grid/hooks/features/columns/useColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ import { ColumnTypesRecord } from '../../../models/colDef/colTypeDef';
import { getColDef } from '../../../models/colDef/getColDef';
import { useApiMethod } from '../../root/useApiMethod';
import { Logger, useLogger } from '../../utils/useLogger';
import { GridState } from '../core/gridState';
import { useGridState } from '../core/useGridState';

function mapColumns(columns: Columns, columnTypes: ColumnTypesRecord): Columns {
return columns.map((c) => ({ ...getColDef(columnTypes, c.type), ...c }));
}

function hydrateColumns(
columns: Columns,
columnTypes: ColumnTypesRecord,
withCheckboxSelection: boolean,
logger: Logger,
): Columns {
logger.debug('Hydrating Columns with default definitions');
let mappedCols = columns.map((c) => ({ ...getColDef(columnTypes, c.type), ...c }));
let mappedCols = mapColumns(columns, columnTypes);
if (withCheckboxSelection) {
mappedCols = [checkboxSelectionColDef, ...mappedCols];
}
Expand Down Expand Up @@ -115,7 +120,6 @@ const getUpdatedColumnState = (
export function useColumns(columns: Columns, apiRef: ApiRef): InternalColumns {
const logger = useLogger('useColumns');
const [gridState, setGridState, forceUpdate] = useGridState(apiRef);

const updateState = React.useCallback(
(newState: InternalColumns, emit = true) => {
logger.debug('Updating columns state.');
Expand All @@ -129,7 +133,7 @@ export function useColumns(columns: Columns, apiRef: ApiRef): InternalColumns {
[logger, setGridState, forceUpdate, apiRef],
);

React.useEffect(() => {
const resetColumns = React.useCallback(() => {
logger.info(`Columns have change, new length ${columns.length}`);
const newState = resetState(
columns,
Expand All @@ -140,32 +144,50 @@ export function useColumns(columns: Columns, apiRef: ApiRef): InternalColumns {
updateState(newState);
}, [
columns,
gridState.options.columnTypes,
gridState.options.checkboxSelection,
gridState.options.columnTypes,
logger,
updateState,
]);

React.useEffect(() => {
resetColumns();
}, [resetColumns]);

const getColumnFromField: (field: string) => ColDef = React.useCallback(
(field) => gridState.columns.lookup[field],
[gridState.columns],
(field) => apiRef.current.getState<GridState>().columns.lookup[field],
[apiRef],
);
const getAllColumns: () => Columns = React.useCallback(
() => apiRef.current.getState<GridState>().columns.all,
[apiRef],
);
const getColumnsMeta: () => ColumnsMeta = React.useCallback(
() => apiRef.current.getState<GridState>().columns.meta,
[apiRef],
);
const getColumnIndex: (field: string, useVisibleColumns?: boolean) => number = React.useCallback(
(field, useVisibleColumns = true) =>
useVisibleColumns
? apiRef.current
.getState<GridState>()
.columns.visible.findIndex((col) => col.field === field)
: apiRef.current.getState<GridState>().columns.all.findIndex((col) => col.field === field),
[apiRef],
);
const getAllColumns: () => Columns = () => gridState.columns.all;
const getColumnsMeta: () => ColumnsMeta = () => gridState.columns.meta;
const getColumnIndex: (field: string, useVisibleColumns?: boolean) => number = (
field,
useVisibleColumns = true,
) =>
useVisibleColumns
? gridState.columns.visible.findIndex((col) => col.field === field)
: gridState.columns.all.findIndex((col) => col.field === field);

const getColumnPosition: (field: string) => number = (field) => {
const index = getColumnIndex(field);
return gridState.columns.meta.positions[index];
};

const getVisibleColumns: () => Columns = () => gridState.columns.visible;
const getColumnPosition: (field: string) => number = React.useCallback(
(field) => {
const index = getColumnIndex(field);
return apiRef.current.getState<GridState>().columns.meta.positions[index];
},
[apiRef, getColumnIndex],
);

const getVisibleColumns: () => Columns = React.useCallback(
() => apiRef.current.getState<GridState>().columns.visible,
[apiRef],
);

const updateColumns = React.useCallback(
(cols: ColDef[], resetColumnState = false) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { KeyboardState } from '../keyboard/keyboardState';
import { INITIAL_PAGINATION_STATE, PaginationState } from '../pagination/paginationReducer';
import { getInitialRowState, InternalRowsState } from '../rows/rowsState';
import { getInitialSortingState, SortingState } from '../sorting/sortingState';
import { ContainerProps } from '../../../models/containerProps';
import { ContainerProps, ScrollBarState, ViewportSizeState } from '../../../models/containerProps';
import {
ColumnReorderState,
getInitialColumnReorderState,
Expand All @@ -21,6 +21,8 @@ export interface GridState {
columnReorder: ColumnReorderState;
rendering: InternalRenderingState;
containerSizes: ContainerProps | null;
viewportSizes: ViewportSizeState;
scrollBar: ScrollBarState;
sorting: SortingState;
keyboard: KeyboardState;
selection: SelectionState;
Expand All @@ -35,6 +37,8 @@ export const getInitialState: () => GridState = () => ({
columnReorder: getInitialColumnReorderState(),
rendering: getInitialRenderingState(),
containerSizes: null,
scrollBar: { hasScrollX: false, hasScrollY: false, scrollBarSize: { x: 0, y: 0 } },
viewportSizes: { width: 0, height: 1 },
sorting: getInitialSortingState(),
keyboard: { cell: null, isMultipleKeyPressed: false },
selection: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const useVirtualColumns = (
apiRef: ApiRef,
): UseVirtualColumnsReturnType => {
const logger = useLogger('useVirtualColumns');

const renderedColRef = React.useRef<RenderColumnsProps | null>(null);
const containerPropsRef = React.useRef<ContainerProps | null>(null);
const lastScrollLeftRef = React.useRef<number>(0);
Expand Down Expand Up @@ -78,10 +79,13 @@ export const useVirtualColumns = (
if (!containerProps) {
return false;
}
containerPropsRef.current = containerProps;
const visibleColumns = apiRef.current.getVisibleColumns();
const columnsMeta = apiRef.current.getColumnsMeta();
const windowSizeChanged =
containerPropsRef.current?.windowSizes.width !== containerProps.windowSizes.width;
containerPropsRef.current = containerProps;
const windowWidth = containerProps.windowSizes.width;

lastScrollLeftRef.current = scrollLeft;
logger.debug(
`Columns from ${getColumnFromScroll(scrollLeft)?.field} to ${
Expand All @@ -105,7 +109,7 @@ export const useVirtualColumns = (

const renderNewColState = diffLast > tolerance || diffFirst > tolerance;

if (!renderedColRef || !renderedColRef.current || renderNewColState) {
if (windowSizeChanged || !renderedColRef || !renderedColRef.current || renderNewColState) {
const newRenderedColState: RenderColumnsProps = {
firstColIdx: firstDisplayedIdx - columnBuffer >= 0 ? firstDisplayedIdx - columnBuffer : 0,
lastColIdx:
Expand All @@ -116,14 +120,14 @@ export const useVirtualColumns = (
rightEmptyWidth: 0,
};
newRenderedColState.leftEmptyWidth = columnsMeta.positions[newRenderedColState.firstColIdx];
if (containerProps.hasScrollX) {
if (apiRef.current.state.scrollBar.hasScrollX) {
newRenderedColState.rightEmptyWidth =
columnsMeta.totalWidth -
columnsMeta.positions[newRenderedColState.lastColIdx] -
visibleColumns[newRenderedColState.lastColIdx].width!;
} else if (!options.disableExtendRowFullWidth) {
newRenderedColState.rightEmptyWidth =
containerProps.viewportSize.width - columnsMeta.totalWidth;
apiRef.current.state.viewportSizes.width - columnsMeta.totalWidth;
}
renderedColRef.current = newRenderedColState;
logger.debug('New columns state to render', newRenderedColState);
Expand All @@ -133,9 +137,8 @@ export const useVirtualColumns = (
return false;
},
[
renderedColRef,
logger,
apiRef,
logger,
getColumnFromScroll,
getColumnIdxFromScroll,
options.columnBuffer,
Expand Down

0 comments on commit a92a543

Please sign in to comment.