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] All selectors accept only apiRef as first argument #16198

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 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 @@ -11,8 +11,7 @@ import {
import { useGridApiContext } from '../hooks/utils/useGridApiContext';
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
import { DataGridPremiumProcessedProps } from '../models/dataGridPremiumProps';
import { GridPrivateApiPremium } from '../models/gridApiPremium';
import { GridStatePremium } from '../models/gridStatePremium';
import { GridApiPremium, GridPrivateApiPremium } from '../models/gridApiPremium';

type OwnerState = DataGridPremiumProcessedProps;

Expand Down Expand Up @@ -43,8 +42,10 @@ function GridGroupingCriteriaCellIcon(props: GridGroupingCriteriaCellIconProps)
const classes = useUtilityClasses(rootProps);
const { rowNode, id, field, descendantCount } = props;

const loadingSelector = (state: GridStatePremium) => state.dataSource.loading[id] ?? false;
const errorSelector = (state: GridStatePremium) => state.dataSource.errors[id];
const loadingSelector = (apiRefObject: React.RefObject<GridApiPremium>) =>
apiRefObject.current.state.dataSource.loading[id] ?? false;
const errorSelector = (apiRefObject: React.RefObject<GridApiPremium>) =>
apiRefObject.current.state.dataSource.errors[id];
Comment on lines -46 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably be selectors with arguments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And rowSelector below as well.

const isDataLoading = useGridSelector(apiRef, loadingSelector);
const error = useGridSelector(apiRef, errorSelector);

Expand Down Expand Up @@ -97,7 +98,8 @@ export function GridDataSourceGroupingCriteriaCell(props: GridGroupingCriteriaCe

const rootProps = useGridRootProps();
const apiRef = useGridApiContext();
const rowSelector = (state: GridStatePremium) => state.rows.dataRowIdToModelLookup[id];
const rowSelector = (apiRefObject: React.RefObject<GridApiPremium>) =>
apiRefObject.current.state.rows.dataRowIdToModelLookup[id];
const row = useGridSelector(apiRef, rowSelector);
const classes = useUtilityClasses(rootProps);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createSelector } from '@mui/x-data-grid-pro/internals';
import { GridStatePremium } from '../../../models/gridStatePremium';
import { GridApiPremium } from '../../../models/gridApiPremium';

export const gridAggregationStateSelector = (state: GridStatePremium) => state.aggregation;
export const gridAggregationStateSelector = (apiRef: React.RefObject<GridApiPremium>) =>
apiRef.current.state.aggregation;
Comment on lines -4 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if creating a createStateSelector that pre-fetches apiRef.current.state could be useful for readability.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a type like GridApiRef*** to make React.RefObject<GridApi***> more compact could also be nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to do that, but have to resolve rendering issues first 🙂


/**
* Get the aggregation model, containing the aggregation function of each column.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GridStatePremium } from '../../../models/gridStatePremium';
import { GridApiPremium } from '../../../models/gridApiPremium';

export const gridCellSelectionStateSelector = (state: GridStatePremium) => state.cellSelection;
export const gridCellSelectionStateSelector = (apiRef: React.RefObject<GridApiPremium>) =>
apiRef.current.state.cellSelection;
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,14 @@ export const useGridCellSelection = (
if (!props.cellSelection) {
return false;
}
const cellSelectionModel = gridCellSelectionStateSelector(apiRef.current.state);
const cellSelectionModel = gridCellSelectionStateSelector(apiRef);
return cellSelectionModel[id] ? !!cellSelectionModel[id][field] : false;
},
[apiRef, props.cellSelection],
);

const getCellSelectionModel = React.useCallback(() => {
return gridCellSelectionStateSelector(apiRef.current.state);
return gridCellSelectionStateSelector(apiRef);
}, [apiRef]);

const setCellSelectionModel = React.useCallback<GridCellSelectionApi['setCellSelectionModel']>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { gridColumnLookupSelector } from '@mui/x-data-grid-pro';
import { createSelector, createSelectorMemoized } from '@mui/x-data-grid/internals';
import { GridStatePremium } from '../../../models/gridStatePremium';
import { GridApiPremium } from '../../../models/gridApiPremium';

const gridRowGroupingStateSelector = (state: GridStatePremium) => state.rowGrouping;
const gridRowGroupingStateSelector = (apiRef: React.RefObject<GridApiPremium>) =>
apiRef.current.state.rowGrouping;

export const gridRowGroupingModelSelector = createSelector(
gridRowGroupingStateSelector,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import {
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
import { useGridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext';
import { DataGridProProcessedProps } from '../models/dataGridProProps';
import { GridPrivateApiPro } from '../models/gridApiPro';
import { GridStatePro } from '../models/gridStatePro';
import { GridApiPro, GridPrivateApiPro } from '../models/gridApiPro';
import {
gridDataSourceErrorSelector,
gridDataSourceLoadingIdSelector,
Expand Down Expand Up @@ -52,8 +51,8 @@ function GridTreeDataGroupingCellIcon(props: GridTreeDataGroupingCellIconProps)
const classes = useUtilityClasses(rootProps);
const { rowNode, id, field, descendantCount } = props;

const isDataLoading = useGridSelector(apiRef, gridDataSourceLoadingIdSelector, id);
const error = useGridSelector(apiRef, gridDataSourceErrorSelector, id);
const isDataLoading = useGridSelector(apiRef, gridDataSourceLoadingIdSelector);
const error = useGridSelector(apiRef, gridDataSourceErrorSelector);
arminmeh marked this conversation as resolved.
Show resolved Hide resolved

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
if (!rowNode.childrenExpanded) {
Expand Down Expand Up @@ -103,7 +102,8 @@ export function GridDataSourceTreeDataGroupingCell(props: GridTreeDataGroupingCe

const rootProps = useGridRootProps();
const apiRef = useGridPrivateApiContext();
const rowSelector = (state: GridStatePro) => state.rows.dataRowIdToModelLookup[id];
const rowSelector = (apiRefObject: React.RefObject<GridApiPro>) =>
apiRefObject.current.state.rows.dataRowIdToModelLookup[id];
const row = useGridSelector(apiRef, rowSelector);
const classes = useUtilityClasses(rootProps);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export const useGridColumnPinning = (

const stateExportPreProcessing = React.useCallback<GridPipeProcessor<'exportState'>>(
(prevState, context) => {
const pinnedColumnsToExport = gridPinnedColumnsSelector(apiRef.current.state);
const pinnedColumnsToExport = gridPinnedColumnsSelector(apiRef);

const shouldExportPinnedColumns =
// Always export if the `exportOnlyDirtyModels` property is not activated
Expand Down Expand Up @@ -227,7 +227,7 @@ export const useGridColumnPinning = (
);

const getPinnedColumns = React.useCallback<GridColumnPinningApi['getPinnedColumns']>(() => {
return gridPinnedColumnsSelector(apiRef.current.state);
return gridPinnedColumnsSelector(apiRef);
}, [apiRef]);
Comment on lines 229 to 231
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should deprecate API methods that only call a selector.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please 👍🏻


const setPinnedColumns = React.useCallback<GridColumnPinningApi['setPinnedColumns']>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const useGridColumnPinningPreProcessors = (

let pinnedColumns: GridPinnedColumnFields | null;
if (apiRef.current.state.columns) {
pinnedColumns = gridPinnedColumnsSelector(apiRef.current.state);
pinnedColumns = gridPinnedColumnsSelector(apiRef);
} else {
pinnedColumns = null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createSelector } from '@mui/x-data-grid/internals';
import { GridStatePro } from '../../../models/gridStatePro';
import { GridApiPro } from '../../../models/gridApiPro';

export const gridColumnReorderSelector = (state: GridStatePro) => state.columnReorder;
export const gridColumnReorderSelector = (apiRef: React.RefObject<GridApiPro>) =>
apiRef.current.state.columnReorder;

export const gridColumnReorderDragColSelector = createSelector(
gridColumnReorderSelector,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
GridRowId,
} from '@mui/x-data-grid';
import { createSelector } from '@mui/x-data-grid/internals';
import { GridStatePro } from '../../../models/gridStatePro';
import { GridApiPro } from '../../../models/gridApiPro';

const computeStartEnd = (paginationModel: GridPaginationModel) => {
const start = paginationModel.page * paginationModel.pageSize;
Expand All @@ -29,7 +29,8 @@ export const gridGetRowsParamsSelector = createSelector(
},
);

export const gridDataSourceStateSelector = (state: GridStatePro) => state.dataSource;
export const gridDataSourceStateSelector = (apiRef: React.RefObject<GridApiPro>) =>
apiRef.current.state.dataSource;

export const gridDataSourceLoadingSelector = createSelector(
gridDataSourceStateSelector,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { createSelectorMemoized } from '@mui/x-data-grid/internals';
import { GridStatePro } from '../../../models/gridStatePro';
import { GridApiPro } from '../../../models/gridApiPro';

const gridDetailPanelStateSelector = (state: GridStatePro) => state.detailPanel;
const gridDetailPanelStateSelector = (apiRef: React.RefObject<GridApiPro>) =>
apiRef.current.state.detailPanel;

export const gridDetailPanelExpandedRowIdsSelector = (state: GridStatePro) =>
state.detailPanel.expandedRowIds;
export const gridDetailPanelExpandedRowIdsSelector = (apiRef: React.RefObject<GridApiPro>) =>
apiRef.current.state.detailPanel.expandedRowIds;

export const gridDetailPanelExpandedRowsContentCacheSelector = (state: GridStatePro) =>
state.detailPanel.contentCache;
export const gridDetailPanelExpandedRowsContentCacheSelector = (
apiRef: React.RefObject<GridApiPro>,
) => apiRef.current.state.detailPanel.contentCache;

export const gridDetailPanelRawHeightCacheSelector = createSelectorMemoized(
gridDetailPanelStateSelector,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const GRID_DETAIL_PANEL_TOGGLE_COL_DEF: GridColDef = {
valueGetter: (value, row, column, apiRef) => {
const rowId = apiRef.current.getRowId(row);
const expandedRowIds = gridDetailPanelExpandedRowIdsSelector(
(apiRef.current as GridApiPro).state,
apiRef as React.RefObject<GridApiPro>,
);
return expandedRowIds.has(rowId);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export const useGridDetailPanel = (
);

const getExpandedDetailPanels = React.useCallback<GridDetailPanelApi['getExpandedDetailPanels']>(
() => gridDetailPanelExpandedRowIdsSelector(apiRef.current.state),
() => gridDetailPanelExpandedRowIdsSelector(apiRef),
[apiRef],
);

Expand Down Expand Up @@ -225,7 +225,7 @@ export const useGridDetailPanel = (

React.useEffect(() => {
if (props.detailPanelExpandedRowIds) {
const currentModel = gridDetailPanelExpandedRowIdsSelector(apiRef.current.state);
const currentModel = gridDetailPanelExpandedRowIdsSelector(apiRef);
if (currentModel !== props.detailPanelExpandedRowIds) {
apiRef.current.setExpandedDetailPanels(props.detailPanelExpandedRowIds);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const useGridDetailPanelPreProcessors = (
return classes;
}

const expandedRowIds = gridDetailPanelExpandedRowIdsSelector(privateApiRef.current.state);
const expandedRowIds = gridDetailPanelExpandedRowIdsSelector(privateApiRef);
if (!expandedRowIds.has(id)) {
return classes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const useGridRowReorder = (
const handleDragStart = React.useCallback<GridEventListener<'rowDragStart'>>(
(params, event) => {
// Call the gridEditRowsStateSelector directly to avoid infnite loop
const editRowsState = gridEditRowsStateSelector(apiRef.current.state);
const editRowsState = gridEditRowsStateSelector(apiRef);
if (isRowReorderDisabled || Object.keys(editRowsState).length !== 0) {
return;
}
Expand Down Expand Up @@ -158,7 +158,7 @@ export const useGridRowReorder = (
const handleDragEnd = React.useCallback<GridEventListener<'rowDragEnd'>>(
(params, event): void => {
// Call the gridEditRowsStateSelector directly to avoid infnite loop
const editRowsState = gridEditRowsStateSelector(apiRef.current.state);
const editRowsState = gridEditRowsStateSelector(apiRef);
if (dragRowId === '' || isRowReorderDisabled || Object.keys(editRowsState).length !== 0) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function GridColumnHeaderFilterIconButton(props: ColumnHeaderFilterIconButtonPro
event.preventDefault();
event.stopPropagation();

const { open, openedPanelValue } = gridPreferencePanelStateSelector(apiRef.current.state);
const { open, openedPanelValue } = gridPreferencePanelStateSelector(apiRef);

if (open && openedPanelValue === GridPreferencePanelsValue.filters) {
apiRef.current.hideFilterPanel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const GridVirtualScrollerRenderZone = forwardRef<
const classes = useUtilityClasses(rootProps);
const offsetTop = useGridSelector(apiRef, () => {
const renderContext = gridRenderContextSelector(apiRef);
const rowsMeta = gridRowsMetaSelector(apiRef.current.state);
const rowsMeta = gridRowsMetaSelector(apiRef);
return rowsMeta.positions[renderContext.firstRowIndex] ?? 0;
});

Expand Down
5 changes: 3 additions & 2 deletions packages/x-data-grid/src/hooks/core/gridCoreSelector.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { GridStateCommunity } from '../../models/gridStateCommunity';
import { GridApiCommunity } from '../../models/api/gridApiCommunity';

/**
* Get the theme state
* @category Core
*/
export const gridIsRtlSelector = (state: GridStateCommunity) => state.isRtl;
export const gridIsRtlSelector = (apiRef: React.RefObject<GridApiCommunity>) =>
apiRef.current.state.isRtl;
3 changes: 2 additions & 1 deletion packages/x-data-grid/src/hooks/core/useGridIsRtl.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { useRtl } from '@mui/system/RtlProvider';
import { GridPrivateApiCommon } from '../../models/api/gridApiCommon';
import { GridStateCommunity } from '../../models/gridStateCommunity';

export const useGridIsRtl = (apiRef: React.RefObject<GridPrivateApiCommon>): void => {
const isRtl = useRtl();
Expand All @@ -14,7 +15,7 @@ export const useGridIsRtl = (apiRef: React.RefObject<GridPrivateApiCommon>): voi
if (isFirstEffect.current) {
isFirstEffect.current = false;
} else {
apiRef.current.setState((state) => ({ ...state, isRtl }));
apiRef.current.setState((state: GridStateCommunity) => ({ ...state, isRtl }));
}
}, [apiRef, isRtl]);
};
23 changes: 9 additions & 14 deletions packages/x-data-grid/src/hooks/core/useGridStateInitialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const useGridStateInitialization = <PrivateApi extends GridPrivateApiComm
const [, rawForceUpdate] = React.useState<PrivateApi['state']>();

const registerControlState = React.useCallback<
GridStatePrivateApi<PrivateApi['state']>['registerControlState']
GridStatePrivateApi<React.RefObject<PrivateApi>>['registerControlState']
>((controlStateItem) => {
controlStateMapRef.current[controlStateItem.stateId] = controlStateItem;
}, []);
Expand All @@ -32,23 +32,18 @@ export const useGridStateInitialization = <PrivateApi extends GridPrivateApiComm
return false;
}

const apiRefWithNewState = apiRef;
apiRefWithNewState.current.state = newState;

let ignoreSetState = false;

// Apply the control state constraints
const updatedControlStateIds: { stateId: string; hasPropChanged: boolean }[] = [];
Object.keys(controlStateMapRef.current).forEach((stateId) => {
const controlState = controlStateMapRef.current[stateId];
const oldSubState = controlState.stateSelector(
apiRef.current.state,
undefined,
apiRef.current.instanceId,
);
const oldSubState = controlState.stateSelector(apiRef);
const newSubState = controlState.stateSelector(apiRefWithNewState);

const newSubState = controlState.stateSelector(
newState,
undefined,
apiRef.current.instanceId,
);
if (newSubState === oldSubState) {
return;
}
Expand Down Expand Up @@ -87,7 +82,7 @@ export const useGridStateInitialization = <PrivateApi extends GridPrivateApiComm
if (updatedControlStateIds.length === 1) {
const { stateId, hasPropChanged } = updatedControlStateIds[0];
const controlState = controlStateMapRef.current[stateId];
const model = controlState.stateSelector(newState, undefined, apiRef.current.instanceId);
const model = controlState.stateSelector(apiRefWithNewState);

if (controlState.propOnChange && hasPropChanged) {
controlState.propOnChange(model, {
Expand All @@ -107,7 +102,7 @@ export const useGridStateInitialization = <PrivateApi extends GridPrivateApiComm
);

const updateControlState = React.useCallback<
GridStatePrivateApi<PrivateApi['state']>['updateControlState']
GridStatePrivateApi<React.RefObject<PrivateApi>>['updateControlState']
>(
(key, state, reason) => {
return apiRef.current.setState((previousState: PrivateApi['state']) => {
Expand All @@ -124,7 +119,7 @@ export const useGridStateInitialization = <PrivateApi extends GridPrivateApiComm
forceUpdate,
};

const privateStateApi: GridStatePrivateApi<PrivateApi['state']> = {
const privateStateApi: GridStatePrivateApi<React.RefObject<PrivateApi>> = {
updateControlState,
registerControlState,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createSelector, createSelectorMemoized } from '../../../utils/createSelector';
import { GridStateCommunity } from '../../../models/gridStateCommunity';
import { GridApiCommunity } from '../../../models/api/gridApiCommunity';

/**
* @category ColumnGrouping
* @ignore - do not document.
*/
export const gridColumnGroupingSelector = (state: GridStateCommunity) => state.columnGrouping;
export const gridColumnGroupingSelector = (apiRef: React.RefObject<GridApiCommunity>) =>
apiRef.current.state.columnGrouping;

export const gridColumnGroupsUnwrappedModelSelector = createSelectorMemoized(
gridColumnGroupingSelector,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GridStateCommunity } from '../../../models/gridStateCommunity';
import { GridApiCommunity } from '../../../models/api/gridApiCommunity';

export const gridColumnMenuSelector = (state: GridStateCommunity) => state.columnMenu;
export const gridColumnMenuSelector = (apiRef: React.RefObject<GridApiCommunity>) =>
apiRef.current.state.columnMenu;
Loading
Loading