diff --git a/docs/data/migration/migration-data-grid-v7/migration-data-grid-v7.md b/docs/data/migration/migration-data-grid-v7/migration-data-grid-v7.md index 55cf6c15cc35..4f3753dd9989 100644 --- a/docs/data/migration/migration-data-grid-v7/migration-data-grid-v7.md +++ b/docs/data/migration/migration-data-grid-v7/migration-data-grid-v7.md @@ -72,6 +72,22 @@ Below are described the steps you need to make to migrate from v7 to v8. - The Grid is more aligned with the WAI-ARIA authoring practices and sets the `role` attribute to `treegrid` if the Data Grid is used with row grouping feature. +### State + +- The selectors signature has been updated due to the support of arguments in the selectors. Pass `undefined` as `arguments` if the selector doesn't use any arguments. + + ```diff + -mySelector(state, instanceId) + +mySelector(state, arguments, instanceId) + ``` + +- The `useGridSelector` signature has been updated due to the introduction of arguments parameter in the selectors. Pass `undefined` as `arguments` if the selector doesn't use any arguments. + + ```diff + -const output = useGridSelector(apiRef, selector, equals) + +const output = useGridSelector(apiRef, selector, arguments, equals) + ``` + ### Other exports - `ariaV8` experimental flag is removed. diff --git a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx index a56f6a8bbc02..172821242fde 100644 --- a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -52,10 +52,7 @@ const GROUPING_COL_DEF_FORCED_PROPERTIES_DATA_SOURCE: Pick< * TODO: Make this index comparator depth invariant, the logic should not be inverted when sorting in the "desc" direction (but the current return format of `sortComparator` does not support this behavior). */ const groupingFieldIndexComparator: GridComparatorFn = (v1, v2, cellParams1, cellParams2) => { - const model = gridRowGroupingSanitizedModelSelector( - cellParams1.api.state, - cellParams1.api.instanceId, - ); + const model = gridRowGroupingSanitizedModelSelector({ current: cellParams1.api }); const groupingField1 = (cellParams1.rowNode as GridGroupNode).groupingField ?? null; const groupingField2 = (cellParams2.rowNode as GridGroupNode).groupingField ?? null; diff --git a/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx b/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx index d5ee7aa79ab5..483958e66591 100644 --- a/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx +++ b/packages/x-data-grid-pro/src/components/GridDataSourceTreeDataGroupingCell.tsx @@ -7,7 +7,6 @@ import { GridDataSourceGroupNode, useGridSelector, } from '@mui/x-data-grid'; -import { useGridSelectorV8 } from '@mui/x-data-grid/internals'; import CircularProgress from '@mui/material/CircularProgress'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; import { useGridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext'; @@ -54,8 +53,8 @@ function GridTreeDataGroupingCellIcon(props: GridTreeDataGroupingCellIconProps) const classes = useUtilityClasses(rootProps); const { rowNode, id, field, descendantCount } = props; - const isDataLoading = useGridSelectorV8(apiRef, gridDataSourceLoadingIdSelector, id); - const error = useGridSelectorV8(apiRef, gridDataSourceErrorSelector, id); + const isDataLoading = useGridSelector(apiRef, gridDataSourceLoadingIdSelector, id); + const error = useGridSelector(apiRef, gridDataSourceErrorSelector, id); const handleClick = (event: React.MouseEvent) => { if (!rowNode.childrenExpanded) { diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/gridDataSourceSelector.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/gridDataSourceSelector.ts index 09e2d34c9099..17d008a6790a 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/gridDataSourceSelector.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/gridDataSourceSelector.ts @@ -5,7 +5,7 @@ import { gridPaginationModelSelector, GridRowId, } from '@mui/x-data-grid'; -import { createSelector, createSelectorV8 } from '@mui/x-data-grid/internals'; +import { createSelector } from '@mui/x-data-grid/internals'; import { GridStatePro } from '../../../models/gridStatePro'; const computeStartEnd = (paginationModel: GridPaginationModel) => { @@ -36,7 +36,7 @@ export const gridDataSourceLoadingSelector = createSelector( (dataSource) => dataSource.loading, ); -export const gridDataSourceLoadingIdSelector = createSelectorV8( +export const gridDataSourceLoadingIdSelector = createSelector( gridDataSourceStateSelector, (dataSource, id: GridRowId) => dataSource.loading[id] ?? false, ); @@ -46,7 +46,7 @@ export const gridDataSourceErrorsSelector = createSelector( (dataSource) => dataSource.errors, ); -export const gridDataSourceErrorSelector = createSelectorV8( +export const gridDataSourceErrorSelector = createSelector( gridDataSourceStateSelector, (dataSource, id: GridRowId) => dataSource.errors[id], ); diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index df53a3c86f1d..c46499ff7692 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -224,6 +224,7 @@ const GridRow = React.forwardRef(function GridRow( const heightEntry = useGridSelector( apiRef, () => ({ ...apiRef.current.getRowHeightEntry(rowId) }), + undefined, objectShallowCompare, ); diff --git a/packages/x-data-grid/src/components/cell/GridCell.tsx b/packages/x-data-grid/src/components/cell/GridCell.tsx index 27bfb3635505..491b78af2ba2 100644 --- a/packages/x-data-grid/src/components/cell/GridCell.tsx +++ b/packages/x-data-grid/src/components/cell/GridCell.tsx @@ -207,6 +207,7 @@ const GridCell = React.forwardRef(function GridCe result.api = apiRef.current; return result; }, + undefined, objectShallowCompare, ); diff --git a/packages/x-data-grid/src/hooks/core/useGridStateInitialization.ts b/packages/x-data-grid/src/hooks/core/useGridStateInitialization.ts index 28cc2b149d4f..05cf991de26b 100644 --- a/packages/x-data-grid/src/hooks/core/useGridStateInitialization.ts +++ b/packages/x-data-grid/src/hooks/core/useGridStateInitialization.ts @@ -9,7 +9,7 @@ export const useGridStateInitialization = , ) => { const controlStateMapRef = React.useRef< - Record> + Record> >({}); const [, rawForceUpdate] = React.useState(); @@ -40,10 +40,15 @@ export const useGridStateInitialization = { apiRef.current.setState((state) => { - const filterModel = gridFilterModelSelector(state, apiRef.current.instanceId); + const filterModel = gridFilterModelSelector(state, undefined, apiRef.current.instanceId); const filterState = apiRef.current.getFilterState(filterModel); const newState = { diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts b/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts index dffb31dbf006..e6780834a556 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRows.ts @@ -359,7 +359,7 @@ export const useGridRows = ( } apiRef.current.setState((state) => { - const group = gridRowTreeSelector(state, apiRef.current.instanceId)[ + const group = gridRowTreeSelector(state, undefined, apiRef.current.instanceId)[ GRID_ROOT_GROUP_ID ] as GridGroupNode; const allRows = group.children; @@ -573,10 +573,10 @@ export const useGridRows = ( const applyHydrateRowsProcessor = React.useCallback(() => { apiRef.current.setState((state) => { const response = apiRef.current.unstable_applyPipeProcessors('hydrateRows', { - tree: gridRowTreeSelector(state, apiRef.current.instanceId), - treeDepths: gridRowTreeDepthsSelector(state, apiRef.current.instanceId), - dataRowIds: gridDataRowIdsSelector(state, apiRef.current.instanceId), - dataRowIdToModelLookup: gridRowsLookupSelector(state, apiRef.current.instanceId), + tree: gridRowTreeSelector(state, undefined, apiRef.current.instanceId), + treeDepths: gridRowTreeDepthsSelector(state, undefined, apiRef.current.instanceId), + dataRowIds: gridDataRowIdsSelector(state, undefined, apiRef.current.instanceId), + dataRowIdToModelLookup: gridRowsLookupSelector(state, undefined, apiRef.current.instanceId), }); return { diff --git a/packages/x-data-grid/src/hooks/features/sorting/useGridSorting.ts b/packages/x-data-grid/src/hooks/features/sorting/useGridSorting.ts index 427306cff45f..ee80de8a0b52 100644 --- a/packages/x-data-grid/src/hooks/features/sorting/useGridSorting.ts +++ b/packages/x-data-grid/src/hooks/features/sorting/useGridSorting.ts @@ -154,7 +154,7 @@ export const useGridSorting = ( }; } - const sortModel = gridSortModelSelector(state, apiRef.current.instanceId); + const sortModel = gridSortModelSelector(state, undefined, apiRef.current.instanceId); const sortRowList = buildAggregatedSortingApplier(sortModel, apiRef); const sortedRows = apiRef.current.applyStrategyProcessor('sorting', { sortRowList, diff --git a/packages/x-data-grid/src/hooks/utils/useGridSelector.ts b/packages/x-data-grid/src/hooks/utils/useGridSelector.ts index 013b904447ee..ca902079c37b 100644 --- a/packages/x-data-grid/src/hooks/utils/useGridSelector.ts +++ b/packages/x-data-grid/src/hooks/utils/useGridSelector.ts @@ -2,34 +2,22 @@ import * as React from 'react'; import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowCompare'; import { warnOnce } from '@mui/x-internals/warning'; import type { GridApiCommon } from '../../models/api/gridApiCommon'; -import type { OutputSelector, OutputSelectorV8 } from '../../utils/createSelector'; +import type { OutputSelector } from '../../utils/createSelector'; import { useLazyRef } from './useLazyRef'; import { useOnMount } from './useOnMount'; import type { GridCoreApi } from '../../models/api/gridCoreApi'; -function isOutputSelector( +function isOutputSelector( selector: any, -): selector is OutputSelector { +): selector is OutputSelector { return selector.acceptsApiRef; } type Selector = | ((state: Api['state']) => T) - | OutputSelectorV8; + | OutputSelector; -// TODO v8: Remove this function -function applySelector( - apiRef: React.MutableRefObject, - selector: ((state: Api['state']) => T) | OutputSelector, -) { - if (isOutputSelector(selector)) { - return selector(apiRef); - } - return selector(apiRef.current.state); -} - -// TODO v8: Rename this function to `applySelector` -function applySelectorV8( +function applySelector( apiRef: React.MutableRefObject, selector: Selector, args: Args, @@ -38,11 +26,11 @@ function applySelectorV8( if (isOutputSelector(selector)) { return selector(apiRef, args); } - return selector(apiRef.current.state, instanceId); + return selector(apiRef.current.state, args, instanceId); } const defaultCompare = Object.is; -export const objectShallowCompare = fastObjectShallowCompare; +export const objectShallowCompare = fastObjectShallowCompare as (a: unknown, b: unknown) => boolean; const arrayShallowCompare = (a: any[], b: any[]) => { if (a === b) { return true; @@ -63,55 +51,7 @@ export const argsEqual = (prev: any, curr: any) => { const createRefs = () => ({ state: null, equals: null, selector: null, args: null }) as any; -// TODO v8: Remove this function -export const useGridSelector = ( - apiRef: React.MutableRefObject, - selector: ((state: Api['state']) => T) | OutputSelector, - equals: (a: T, b: T) => boolean = defaultCompare, -) => { - if (process.env.NODE_ENV !== 'production') { - if (!apiRef.current.state) { - warnOnce([ - 'MUI X: `useGridSelector` has been called before the initialization of the state.', - 'This hook can only be used inside the context of the grid.', - ]); - } - } - - const refs = useLazyRef< - { - state: T; - equals: typeof equals; - selector: typeof selector; - }, - never - >(createRefs); - const didInit = refs.current.selector !== null; - - const [state, setState] = React.useState( - // We don't use an initialization function to avoid allocations - (didInit ? null : applySelector(apiRef, selector)) as T, - ); - - refs.current.state = state; - refs.current.equals = equals; - refs.current.selector = selector; - - useOnMount(() => { - return apiRef.current.store.subscribe(() => { - const newState = applySelector(apiRef, refs.current.selector); - if (!refs.current.equals(refs.current.state, newState)) { - refs.current.state = newState; - setState(newState); - } - }); - }); - - return state; -}; - -// TODO v8: Rename this function to `useGridSelector` -export const useGridSelectorV8 = ( +export const useGridSelector = ( apiRef: React.MutableRefObject, selector: Selector, args: Args = undefined as Args, @@ -139,7 +79,7 @@ export const useGridSelectorV8 = ( const [state, setState] = React.useState( // We don't use an initialization function to avoid allocations - (didInit ? null : applySelectorV8(apiRef, selector, args, apiRef.current.instanceId)) as T, + (didInit ? null : applySelector(apiRef, selector, args, apiRef.current.instanceId)) as T, ); refs.current.state = state; @@ -149,7 +89,7 @@ export const useGridSelectorV8 = ( refs.current.args = args; if (didInit && !argsEqual(prevArgs, args)) { - const newState = applySelectorV8( + const newState = applySelector( apiRef, refs.current.selector, refs.current.args, @@ -163,7 +103,7 @@ export const useGridSelectorV8 = ( useOnMount(() => { return apiRef.current.store.subscribe(() => { - const newState = applySelectorV8( + const newState = applySelector( apiRef, refs.current.selector, refs.current.args, diff --git a/packages/x-data-grid/src/internals/index.ts b/packages/x-data-grid/src/internals/index.ts index d2feea4b7c28..60848709e192 100644 --- a/packages/x-data-grid/src/internals/index.ts +++ b/packages/x-data-grid/src/internals/index.ts @@ -151,13 +151,7 @@ export type * from '../models/props/DataGridProps'; export type * from '../models/gridDataSource'; export { getColumnsToExport, defaultGetRowsToExport } from '../hooks/features/export/utils'; export * from '../utils/createControllablePromise'; -export { - createSelector, - createSelectorV8, - createSelectorMemoized, - createSelectorMemoizedV8, -} from '../utils/createSelector'; -export { useGridSelectorV8 } from '../hooks/utils/useGridSelector'; +export { createSelector, createSelectorMemoized } from '../utils/createSelector'; export { gridRowGroupsToFetchSelector } from '../hooks/features/rows/gridRowsSelector'; export { findParentElementFromClassName, diff --git a/packages/x-data-grid/src/models/api/gridStateApi.ts b/packages/x-data-grid/src/models/api/gridStateApi.ts index f2a8929c6a57..a1c88c022ede 100644 --- a/packages/x-data-grid/src/models/api/gridStateApi.ts +++ b/packages/x-data-grid/src/models/api/gridStateApi.ts @@ -42,7 +42,7 @@ export interface GridStatePrivateApi { * Updates a control state that binds the model, the onChange prop, and the grid state together. * @param {GridControlStateItem>} controlState The [[GridControlStateItem]] to be registered. */ - registerControlState: ( - controlState: GridControlStateItem, + registerControlState: ( + controlState: GridControlStateItem, ) => void; } diff --git a/packages/x-data-grid/src/models/controlStateItem.ts b/packages/x-data-grid/src/models/controlStateItem.ts index 7e20416696d0..0951cc5f565c 100644 --- a/packages/x-data-grid/src/models/controlStateItem.ts +++ b/packages/x-data-grid/src/models/controlStateItem.ts @@ -5,12 +5,13 @@ import { GridStateCommunity } from './gridStateCommunity'; export interface GridControlStateItem< State extends GridStateCommunity, + Args, E extends keyof GridControlledStateEventLookup, > { stateId: string; propModel?: GridEventLookup[E]['params']; stateSelector: - | OutputSelector + | OutputSelector | ((state: State) => GridControlledStateEventLookup[E]['params']); propOnChange?: ( model: GridControlledStateEventLookup[E]['params'], diff --git a/packages/x-data-grid/src/utils/createSelector.spec.ts b/packages/x-data-grid/src/utils/createSelector.spec.ts index 3d0883901fa1..cdd9c8da122f 100644 --- a/packages/x-data-grid/src/utils/createSelector.spec.ts +++ b/packages/x-data-grid/src/utils/createSelector.spec.ts @@ -33,7 +33,7 @@ createSelector( createSelector( (state: GridStateCommunity) => state.columns.orderedFields, (fields) => fields, -)({} as GridStateCommunity, { id: 1 }); +)({} as GridStateCommunity, undefined, { id: 1 }); createSelector( // @ts-expect-error Wrong state key diff --git a/packages/x-data-grid/src/utils/createSelector.test.ts b/packages/x-data-grid/src/utils/createSelector.test.ts index b77cde1019a4..bfdee6c93cdf 100644 --- a/packages/x-data-grid/src/utils/createSelector.test.ts +++ b/packages/x-data-grid/src/utils/createSelector.test.ts @@ -9,21 +9,23 @@ describe('createSelector', () => { it('should warn if the instance ID is missing', () => { const selector = createSelectorMemoized([], () => []); const state = {} as GridStateCommunity; - // @ts-expect-error Need to test the warning expect(() => selector(state)).toWarnDev( 'MUI X: A selector was called without passing the instance ID, which may impact the performance of the grid.', ); - expect(() => selector(state, { id: 0 })).not.toWarnDev(); + expect(() => selector(state, undefined, { id: 0 })).not.toWarnDev(); }); it('should fallback to the default behavior when no cache key is provided', () => { const selector = createSelectorMemoized([], () => []) as OutputSelector< GridStateCommunity, + any, any >; const state = {} as GridStateCommunity; const instanceId = { id: 0 }; - expect(selector(state, instanceId)).to.equal(selector(state, instanceId)); + expect(selector(state, undefined, instanceId)).to.equal( + selector(state, undefined, instanceId), + ); }); it('should clear the cached value when another state is passed', () => { @@ -33,13 +35,13 @@ describe('createSelector', () => { ); const state1 = {} as GridStateCommunity; const state2 = {} as GridStateCommunity; - const value1 = selector(state1, { id: 1 }); + const value1 = selector(state1, undefined, { id: 1 }); // The default cache has maxSize=1, which forces a recomputation if another state is passed. // Since the combiner function returns a new array, the references won't be the same. - selector(state2, { id: 1 }); + selector(state2, undefined, { id: 1 }); - const value2 = selector(state1, { id: 1 }); + const value2 = selector(state1, undefined, { id: 1 }); expect(value1).not.to.equal(value2); }); }); @@ -48,6 +50,7 @@ describe('createSelector', () => { it('should return different selectors for different cache keys', () => { const selector = createSelectorMemoized([], () => []) as OutputSelector< GridStateCommunity, + any, any >; const apiRef1 = { @@ -62,6 +65,7 @@ describe('createSelector', () => { it('should not clear the cache of one selector when another key is passed', () => { const selector = createSelectorMemoized([], () => []) as OutputSelector< GridStateCommunity, + any, any >; const apiRef1 = { diff --git a/packages/x-data-grid/src/utils/createSelector.ts b/packages/x-data-grid/src/utils/createSelector.ts index ec6c0bf352de..a574c2e80ae0 100644 --- a/packages/x-data-grid/src/utils/createSelector.ts +++ b/packages/x-data-grid/src/utils/createSelector.ts @@ -18,20 +18,12 @@ type GridCreateSelectorFunction = ReturnType & { selectorArgs?: any; }; -// TODO v8: Remove this type -export interface OutputSelector { - (apiRef: React.MutableRefObject<{ state: State; instanceId: GridCoreApi['instanceId'] }>): Result; - (state: State, instanceId: GridCoreApi['instanceId']): Result; - acceptsApiRef: boolean; -} - -// TODO v8: Rename this type to `OutputSelector` -export interface OutputSelectorV8 { +export interface OutputSelector { ( apiRef: React.MutableRefObject<{ state: State; instanceId: GridCoreApi['instanceId'] }>, args?: Args, ): Result; - (state: State, instanceId: GridCoreApi['instanceId']): Result; + (state: State, args?: Args, instanceId?: GridCoreApi['instanceId']): Result; acceptsApiRef: boolean; } @@ -50,20 +42,12 @@ type StateFromSelectorList = Selectors extends : StateFromSelectorList : {}; -// TODO v8: Remove this type -type SelectorArgs>, Result> = - // Input selectors as a separate array - | [selectors: [...Selectors], combiner: (...args: SelectorResultArray) => Result] - // Input selectors as separate inline arguments - | [...Selectors, (...args: SelectorResultArray) => Result]; - type SelectorResultArrayWithArgs>, Args> = [ ...SelectorResultArray, Args, ]; -// TODO v8: Rename this type to `SelectorArgs` -type SelectorArgsV8>, Args, Result> = +type SelectorArgs>, Args, Result> = // Input selectors as a separate array | [ selectors: [...Selectors], @@ -72,15 +56,9 @@ type SelectorArgsV8>, Args, Result // Input selectors as separate inline arguments | [...Selectors, (...args: SelectorResultArrayWithArgs) => Result]; -// TODO v8: Remove this type -type CreateSelectorFunction = >, Result>( - ...items: SelectorArgs -) => OutputSelector, Result>; - -// TODO v8: Rename this type to `CreateSelectorFunction` -type CreateSelectorFunctionV8 = >, Args, Result>( - ...items: SelectorArgsV8 -) => OutputSelectorV8, Args, Result>; +type CreateSelectorFunction = >, Args, Result>( + ...items: SelectorArgs +) => OutputSelector, Args, Result>; const cache = new WeakMap>(); @@ -90,7 +68,6 @@ function checkIsAPIRef(value: any) { const DEFAULT_INSTANCE_ID = { id: 'default' }; -// TODO v8: Remove this function export const createSelector = (( a: Function, b: Function, @@ -107,91 +84,6 @@ export const createSelector = (( let selector: any; - // eslint-disable-next-line id-denylist - if (a && b && c && d && e && f) { - selector = (stateOrApiRef: any, instanceIdParam: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const instanceId = - instanceIdParam ?? (isAPIRef ? stateOrApiRef.current.instanceId : DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - const va = a(state, instanceId); - const vb = b(state, instanceId); - const vc = c(state, instanceId); - const vd = d(state, instanceId); - const ve = e(state, instanceId); - return f(va, vb, vc, vd, ve); - }; - // eslint-disable-next-line id-denylist - } else if (a && b && c && d && e) { - selector = (stateOrApiRef: any, instanceIdParam: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const instanceId = - instanceIdParam ?? (isAPIRef ? stateOrApiRef.current.instanceId : DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - const va = a(state, instanceId); - const vb = b(state, instanceId); - const vc = c(state, instanceId); - const vd = d(state, instanceId); - return e(va, vb, vc, vd); - }; - } else if (a && b && c && d) { - selector = (stateOrApiRef: any, instanceIdParam: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const instanceId = - instanceIdParam ?? (isAPIRef ? stateOrApiRef.current.instanceId : DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - const va = a(state, instanceId); - const vb = b(state, instanceId); - const vc = c(state, instanceId); - return d(va, vb, vc); - }; - } else if (a && b && c) { - selector = (stateOrApiRef: any, instanceIdParam: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const instanceId = - instanceIdParam ?? (isAPIRef ? stateOrApiRef.current.instanceId : DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - const va = a(state, instanceId); - const vb = b(state, instanceId); - return c(va, vb); - }; - } else if (a && b) { - selector = (stateOrApiRef: any, instanceIdParam: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const instanceId = - instanceIdParam ?? (isAPIRef ? stateOrApiRef.current.instanceId : DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - const va = a(state, instanceId); - return b(va); - }; - } else { - throw new Error('Missing arguments'); - } - - // We use this property to detect if the selector was created with createSelector - // or it's only a simple function the receives the state and returns part of it. - selector.acceptsApiRef = true; - - return selector; -}) as unknown as CreateSelectorFunction; - -// TODO v8: Rename this function to `createSelector` -export const createSelectorV8 = (( - a: Function, - b: Function, - c?: Function, - d?: Function, - // eslint-disable-next-line id-denylist - e?: Function, - f?: Function, - ...other: any[] -) => { - if (other.length > 0) { - throw new Error('Unsupported number of selectors'); - } - - let selector: any; - // eslint-disable-next-line id-denylist if (a && b && c && d && e && f) { selector = (stateOrApiRef: any, args: any, instanceIdParam: any) => { @@ -258,55 +150,9 @@ export const createSelectorV8 = (( selector.acceptsApiRef = true; return selector; -}) as unknown as CreateSelectorFunctionV8; +}) as unknown as CreateSelectorFunction; -// TODO v8: Remove this function export const createSelectorMemoized: CreateSelectorFunction = (...args: any) => { - const selector = (stateOrApiRef: any, instanceId?: any) => { - const isAPIRef = checkIsAPIRef(stateOrApiRef); - const cacheKey = isAPIRef - ? stateOrApiRef.current.instanceId - : (instanceId ?? DEFAULT_INSTANCE_ID); - const state = isAPIRef ? stateOrApiRef.current.state : stateOrApiRef; - - if (process.env.NODE_ENV !== 'production') { - if (cacheKey.id === 'default') { - warnOnce([ - 'MUI X: A selector was called without passing the instance ID, which may impact the performance of the grid.', - 'To fix, call it with `apiRef`, for example `mySelector(apiRef)`, or pass the instance ID explicitly, for example `mySelector(state, apiRef.current.instanceId)`.', - ]); - } - } - - const cacheArgsInit = cache.get(cacheKey); - const cacheArgs = cacheArgsInit ?? new Map(); - const cacheFn = cacheArgs?.get(args); - - if (cacheArgs && cacheFn) { - // We pass the cache key because the called selector might have as - // dependency another selector created with this `createSelector`. - return cacheFn(state, cacheKey); - } - - const fn = reselectCreateSelector(...args); - - if (!cacheArgsInit) { - cache.set(cacheKey, cacheArgs); - } - cacheArgs.set(args, fn); - - return fn(state, cacheKey); - }; - - // We use this property to detect if the selector was created with createSelector - // or it's only a simple function the receives the state and returns part of it. - selector.acceptsApiRef = true; - - return selector; -}; - -// TODO v8: Rename this function to `createSelectorMemoized` -export const createSelectorMemoizedV8: CreateSelectorFunctionV8 = (...args: any) => { const selector = (stateOrApiRef: any, selectorArgs: any, instanceId?: any) => { const isAPIRef = checkIsAPIRef(stateOrApiRef); const cacheKey = isAPIRef @@ -318,7 +164,7 @@ export const createSelectorMemoizedV8: CreateSelectorFunctionV8 = (...args: any) if (cacheKey.id === 'default') { warnOnce([ 'MUI X: A selector was called without passing the instance ID, which may impact the performance of the grid.', - 'To fix, call it with `apiRef`, for example `mySelector(apiRef)`, or pass the instance ID explicitly, for example `mySelector(state, apiRef.current.instanceId)`.', + 'To fix, call it with `apiRef`, for example `mySelector(apiRef)`, or pass the instance ID explicitly, for example `mySelector(state, args, apiRef.current.instanceId)`.', ]); } }