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

[core] Use selectors instead of direct state access in feature hooks and components #2723

Merged
merged 4 commits into from
Oct 5, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { GridRootContainerRef } from '../../models/gridRootContainerRef';
import { useStyles } from './GridRootStyles';
import { visibleGridColumnsLengthSelector } from '../../hooks/features/columns/gridColumnsSelector';
import { useGridSelector } from '../../hooks/features/core/useGridSelector';
import { useGridState } from '../../hooks/features/core/useGridState';
import { useGridApiContext } from '../../hooks/root/useGridApiContext';
import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
import { gridClasses } from '../../gridClasses';
import { gridRowCountSelector } from '../../hooks/features/rows/gridRowsSelector';

export type GridRootProps = React.HTMLAttributes<HTMLDivElement>;

Expand All @@ -22,7 +22,7 @@ export const GridRoot = React.forwardRef<HTMLDivElement, GridRootProps>(function
const rootProps = useGridRootProps();
const { children, className: classNameProp, ...other } = props;
const visibleColumnsLength = useGridSelector(apiRef, visibleGridColumnsLengthSelector);
const [gridState] = useGridState(apiRef);
const totalRowCount = useGridSelector(apiRef, gridRowCountSelector);
const rootContainerRef: GridRootContainerRef = React.useRef<HTMLDivElement>(null);
const handleRef = useForkRef(rootContainerRef, ref);

Expand All @@ -44,7 +44,7 @@ export const GridRoot = React.forwardRef<HTMLDivElement, GridRootProps>(function
)}
role="grid"
aria-colcount={visibleColumnsLength}
aria-rowcount={gridState.rows.totalRowCount}
aria-rowcount={totalRowCount}
aria-multiselectable={!rootProps.disableMultipleSelection}
aria-label={rootProps['aria-label']}
aria-labelledby={rootProps['aria-labelledby']}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import { useGridState } from '../../../hooks/features/core/useGridState';
import { GridFilterItem, GridLinkOperator } from '../../../models/gridFilterItem';
import { useGridApiContext } from '../../../hooks/root/useGridApiContext';
import { GridAddIcon } from '../../icons/index';
import { GridAddIcon } from '../../icons';
import { GridPanelContent } from '../GridPanelContent';
import { GridPanelFooter } from '../GridPanelFooter';
import { GridPanelWrapper } from '../GridPanelWrapper';
import { GridFilterForm } from './GridFilterForm';
import { useGridRootProps } from '../../../hooks/utils/useGridRootProps';
import { useGridSelector } from '../../../hooks/features/core/useGridSelector';
import { gridFilterModelSelector } from '../../../hooks/features/filter/gridFilterSelector';

export function GridFilterPanel() {
const apiRef = useGridApiContext();
const [gridState] = useGridState(apiRef);
const rootProps = useGridRootProps();
const filterModel = useGridSelector(apiRef, gridFilterModelSelector);

const hasMultipleFilters = React.useMemo(
() => gridState.filter.items.length > 1,
[gridState.filter.items.length],
);
const hasMultipleFilters = filterModel.items.length > 1;

const applyFilter = React.useCallback(
(item: GridFilterItem) => {
Expand Down Expand Up @@ -46,23 +44,23 @@ export function GridFilterPanel() {
);

React.useEffect(() => {
if (gridState.filter.items.length === 0) {
if (filterModel.items.length === 0) {
addNewFilter();
}
}, [addNewFilter, gridState.filter.items.length]);
}, [addNewFilter, filterModel.items.length]);

return (
<GridPanelWrapper>
<GridPanelContent>
{gridState.filter.items.map((item, index) => (
{filterModel.items.map((item, index) => (
<GridFilterForm
key={item.id == null ? index : item.id}
item={item}
applyFilterChanges={applyFilter}
deleteFilter={deleteFilter}
hasMultipleFilters={hasMultipleFilters}
showMultiFilterOperators={index > 0}
multiFilterOperator={gridState.filter.linkOperator}
multiFilterOperator={filterModel.linkOperator}
disableMultiFilterOperator={index !== 1}
applyMultiFilterOperatorChanges={applyFilterLinkOperator}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import { GridColumnOrderChangeParams } from '../../../models/params/gridColumnOr
import { mergeGridColTypes } from '../../../utils/mergeUtils';
import { useGridApiMethod } from '../../root/useGridApiMethod';
import { useGridLogger } from '../../utils/useGridLogger';
import { useGridSelector } from '../core/useGridSelector';
import { GridLocaleText, GridTranslationKeys } from '../../../models/api/gridLocaleTextApi';
import { useGridState } from '../core/useGridState';
import {
allGridColumnsFieldsSelector,
allGridColumnsSelector,
gridColumnsMetaSelector,
gridColumnsSelector,
visibleGridColumnsSelector,
} from './gridColumnsSelector';
import { useGridApiOptionHandler } from '../../root/useGridApiEventHandler';
Expand Down Expand Up @@ -156,9 +157,6 @@ export function useGridColumns(
): void {
const logger = useGridLogger(apiRef, 'useGridColumns');
const [gridState, setGridState, forceUpdate] = useGridState(apiRef);
const columnsMeta = useGridSelector(apiRef, gridColumnsMetaSelector);
const allColumns = useGridSelector(apiRef, allGridColumnsSelector);
const visibleColumns = useGridSelector(apiRef, visibleGridColumnsSelector);
const ownerState = { classes: props.classes };
const classes = useUtilityClasses(ownerState);

Expand All @@ -182,32 +180,35 @@ export function useGridColumns(
);

const getAllColumns = React.useCallback<GridColumnApi['getAllColumns']>(
() => allColumns,
[allColumns],
() => allGridColumnsSelector(apiRef.current.state),
[apiRef],
);
const getVisibleColumns = React.useCallback<GridColumnApi['getVisibleColumns']>(
() => visibleColumns,
[visibleColumns],
() => visibleGridColumnsSelector(apiRef.current.state),
[apiRef],
);
const getColumnsMeta = React.useCallback<GridColumnApi['getColumnsMeta']>(
() => columnsMeta,
[columnsMeta],
() => gridColumnsMetaSelector(apiRef.current.state),
[apiRef],
);

const getColumnIndex = React.useCallback(
(field: string, useVisibleColumns: boolean = true): number =>
useVisibleColumns
? visibleColumns.findIndex((col) => col.field === field)
: allColumns.findIndex((col) => col.field === field),
[allColumns, visibleColumns],
(field: string, useVisibleColumns: boolean = true): number => {
const columns = useVisibleColumns
? visibleGridColumnsSelector(apiRef.current.state)
: allGridColumnsSelector(apiRef.current.state);

return columns.findIndex((col) => col.field === field);
},
[apiRef],
);

const getColumnPosition: (field: string) => number = React.useCallback(
(field) => {
const index = getColumnIndex(field);
return columnsMeta.positions[index];
return gridColumnsMetaSelector(apiRef.current.state).positions[index];
},
[columnsMeta.positions, getColumnIndex],
[apiRef, getColumnIndex],
);

const setColumnsState = React.useCallback(
Expand Down Expand Up @@ -264,16 +265,17 @@ export function useGridColumns(

const setColumnIndex = React.useCallback(
(field: string, targetIndexPosition: number) => {
const oldIndexPosition = gridState.columns.all.findIndex((col) => col === field);
const allColumns = allGridColumnsFieldsSelector(apiRef.current.state);
const oldIndexPosition = allColumns.findIndex((col) => col === field);
if (oldIndexPosition === targetIndexPosition) {
return;
}

logger.debug(`Moving column ${field} to index ${targetIndexPosition}`);

const updatedColumns = [...gridState.columns.all];
const updatedColumns = [...allColumns];
updatedColumns.splice(targetIndexPosition, 0, updatedColumns.splice(oldIndexPosition, 1)[0]);
setGridColumnsState({ ...gridState.columns, all: updatedColumns });
setGridColumnsState({ ...gridColumnsSelector(apiRef.current.state), all: updatedColumns });

const params: GridColumnOrderChangeParams = {
field,
Expand All @@ -284,7 +286,7 @@ export function useGridColumns(
};
apiRef.current.publishEvent(GridEvents.columnOrderChange, params);
},
[apiRef, gridState.columns, logger, setGridColumnsState],
[apiRef, logger, setGridColumnsState],
);

const setColumnWidth = React.useCallback(
Expand Down
11 changes: 4 additions & 7 deletions packages/grid/_modules_/grid/hooks/features/core/gridState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
getInitialGridColumnResizeState,
GridColumnResizeState,
} from '../columnResize/columnResizeState';
import { GridGridDensity, getInitialGridDensityState } from '../density/densityState';
import { GridDensityState, getInitialGridDensityState } from '../density/densityState';
import { getInitialGridFilterState } from '../filter/gridFilterModelState';
import {
getInitialVisibleGridRowsState,
Expand All @@ -26,10 +26,7 @@ import { GridPreferencePanelState } from '../preferencesPanel/gridPreferencePane
import { getInitialGridRowState, GridRowsState } from '../rows/gridRowsState';
import { GridSelectionModel } from '../../../models/gridSelectionModel';
import { getInitialGridSortingState, GridSortingState } from '../sorting/gridSortingState';
import {
getInitialGridRenderingState,
InternalRenderingState,
} from '../virtualization/renderingState';
import { getInitialGridRenderingState, GridRenderingState } from '../virtualization/renderingState';
import { getInitialPaginationState, GridPaginationState } from '../pagination/gridPaginationState';

export interface GridState {
Expand All @@ -40,7 +37,7 @@ export interface GridState {
columnReorder: GridColumnReorderState;
columnResize: GridColumnResizeState;
columnMenu: GridColumnMenuState;
rendering: InternalRenderingState;
rendering: GridRenderingState;
containerSizes: GridContainerProps | null;
viewportSizes: GridViewportSizeState;
scrollBar: GridScrollBarState;
Expand All @@ -51,7 +48,7 @@ export interface GridState {
filter: GridFilterModel;
visibleRows: VisibleGridRowsState;
preferencePanel: GridPreferencePanelState;
density: GridGridDensity;
density: GridDensityState;
error?: any;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { createSelector } from 'reselect';
import { GridState } from '../core/gridState';

export const densitySelector = (state: GridState) => state.density;
export const gridDensitySelector = (state: GridState) => state.density;

export const gridDensityValueSelector = createSelector(densitySelector, (density) => density.value);
export const gridDensityValueSelector = createSelector(
gridDensitySelector,
(density) => density.value,
);

export const gridDensityRowHeightSelector = createSelector(
densitySelector,
gridDensitySelector,
(density) => density.rowHeight,
);

export const gridDensityHeaderHeightSelector = createSelector(
densitySelector,
gridDensitySelector,
(density) => density.headerHeight,
);
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { GridDensity, GridDensityTypes } from '../../../models/gridDensity';

export interface GridGridDensity {
export interface GridDensityState {
value: GridDensity;
rowHeight: number;
headerHeight: number;
}

export function getInitialGridDensityState(): GridGridDensity {
export function getInitialGridDensityState(): GridDensityState {
return {
value: GridDensityTypes.Standard,
rowHeight: 52,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,46 @@ import { GridApiRef } from '../../../models/api/gridApiRef';
import { useGridApiMethod } from '../../root/useGridApiMethod';
import { useGridState } from '../core/useGridState';
import { GridDensityApi } from '../../../models/api/gridDensityApi';
import { GridGridDensity } from './densityState';
import { GridDensityState } from './densityState';
import { GridComponentProps } from '../../../GridComponentProps';

export const COMPACT_DENSITY_FACTOR = 0.7;
export const COMFORTABLE_DENSITY_FACTOR = 1.3;

const getUpdatedDensityState = (
newDensity: GridDensity,
newHeaderHeight: number,
newRowHeight: number,
): GridDensityState => {
switch (newDensity) {
case GridDensityTypes.Compact:
return {
value: newDensity,
headerHeight: Math.floor(newHeaderHeight * COMPACT_DENSITY_FACTOR),
rowHeight: Math.floor(newRowHeight * COMPACT_DENSITY_FACTOR),
};
case GridDensityTypes.Comfortable:
return {
value: newDensity,
headerHeight: Math.floor(newHeaderHeight * COMFORTABLE_DENSITY_FACTOR),
rowHeight: Math.floor(newRowHeight * COMFORTABLE_DENSITY_FACTOR),
};
default:
return {
value: newDensity,
headerHeight: newHeaderHeight,
rowHeight: newRowHeight,
};
}
};

export const useGridDensity = (
apiRef: GridApiRef,
props: Pick<GridComponentProps, 'headerHeight' | 'rowHeight' | 'density'>,
): void => {
const logger = useGridLogger(apiRef, 'useDensity');
const [, setGridState, forceUpdate] = useGridState(apiRef);

const getUpdatedDensityState = React.useCallback(
(newDensity: GridDensity, newHeaderHeight: number, newRowHeight: number): GridGridDensity => {
switch (newDensity) {
case GridDensityTypes.Compact:
return {
value: newDensity,
headerHeight: Math.floor(newHeaderHeight * COMPACT_DENSITY_FACTOR),
rowHeight: Math.floor(newRowHeight * COMPACT_DENSITY_FACTOR),
};
case GridDensityTypes.Comfortable:
return {
value: newDensity,
headerHeight: Math.floor(newHeaderHeight * COMFORTABLE_DENSITY_FACTOR),
rowHeight: Math.floor(newRowHeight * COMFORTABLE_DENSITY_FACTOR),
};
default:
return {
value: newDensity,
headerHeight: newHeaderHeight,
rowHeight: newRowHeight,
};
}
},
[],
);

const setDensity = React.useCallback(
(
newDensity: GridDensity,
Expand All @@ -60,14 +61,7 @@ export const useGridDensity = (
}));
forceUpdate();
},
[
logger,
setGridState,
forceUpdate,
getUpdatedDensityState,
props.headerHeight,
props.rowHeight,
],
[logger, setGridState, forceUpdate, props.headerHeight, props.rowHeight],
);

React.useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ export const visibleGridRowCountSelector = createSelector(
},
);

export const filterGridStateSelector = (state: GridState) => state.filter;
export const gridFilterModelSelector = (state: GridState) => state.filter;

export const activeGridFilterItemsSelector = createSelector(
filterGridStateSelector,
gridFilterModelSelector,
gridColumnLookupSelector,
(filterModel, columnLookup) =>
filterModel.items?.filter((item) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { GridPreferencePanelsValue } from '../preferencesPanel/gridPreferencePan
import { sortedGridRowsSelector } from '../sorting/gridSortingSelector';
import { getInitialGridFilterState } from './gridFilterModelState';
import { GridFilterModel } from '../../../models/gridFilterModel';
import { visibleSortedGridRowsSelector } from './gridFilterSelector';
import { gridFilterModelSelector, visibleSortedGridRowsSelector } from './gridFilterSelector';
import { getInitialVisibleGridRowsState } from './visibleGridRowsState';

/**
Expand Down Expand Up @@ -278,11 +278,11 @@ export const useGridFilter = (

const onColUpdated = React.useCallback(() => {
logger.debug('onColUpdated - GridColumns changed, applying filters');
const filterState = apiRef.current.state.filter;
const filterModel = gridFilterModelSelector(apiRef.current.state);
const columnsIds = filterableGridColumnsIdsSelector(apiRef.current.state);
logger.debug('GridColumns changed, applying filters');

filterState.items.forEach((filter) => {
filterModel.items.forEach((filter) => {
if (!columnsIds.find((field) => field === filter.columnField)) {
apiRef.current.deleteFilter(filter);
}
Expand Down
Loading