Skip to content

Commit

Permalink
[DataGridPro] Use Set for detailPanelExpandedRowIds (#15835)
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii authored Dec 16, 2024
1 parent cf8e3ef commit 45e01cf
Show file tree
Hide file tree
Showing 31 changed files with 169 additions and 192 deletions.
2 changes: 1 addition & 1 deletion docs/data/data-grid/master-detail/ControlMasterDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Alert from '@mui/material/Alert';

export default function ControlMasterDetail() {
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState(
[],
() => new Set(),
);

const handleDetailPanelExpandedRowIdsChange = React.useCallback((newIds) => {
Expand Down
18 changes: 9 additions & 9 deletions docs/data/data-grid/master-detail/ControlMasterDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GridColDef,
GridRowsProp,
GridRowId,
DataGridProProps,
} from '@mui/x-data-grid-pro';
import {
randomCreatedDate,
Expand All @@ -15,17 +16,16 @@ import {
import Alert from '@mui/material/Alert';

export default function ControlMasterDetail() {
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState<
GridRowId[]
>([]);

const handleDetailPanelExpandedRowIdsChange = React.useCallback(
(newIds: GridRowId[]) => {
setDetailPanelExpandedRowIds(newIds);
},
[],
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState(
() => new Set<GridRowId>(),
);

const handleDetailPanelExpandedRowIdsChange = React.useCallback<
NonNullable<DataGridProProps['onDetailPanelExpandedRowIdsChange']>
>((newIds) => {
setDetailPanelExpandedRowIds(newIds);
}, []);

return (
<Box sx={{ width: '100%' }}>
<Alert severity="info">
Expand Down
14 changes: 6 additions & 8 deletions docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function DetailPanelContent({ row: rowProp }) {
// Store the data in cache so that when detail panel unmounts due to virtualization, the data is not lost
detailPanelDataCache.set(rowProp.id, response);
}

const result = detailPanelDataCache.get(rowProp.id);

if (!isMounted) {
Expand Down Expand Up @@ -125,14 +126,11 @@ export default function LazyLoadingDetailPanel() {
const handleDetailPanelExpansionChange = React.useCallback(
(newExpandedRowIds) => {
// Only keep cached data for detail panels that are still expanded
const preservedEntries = newExpandedRowIds.map((id) => [
id,
detailPanelDataCache.get(id),
]);
detailPanelDataCache.clear();
preservedEntries.forEach(
([id, value]) => value && detailPanelDataCache.set(id, value),
);
for (const [id] of detailPanelDataCache) {
if (!newExpandedRowIds.has(id)) {
detailPanelDataCache.delete(id);
}
}
},
[detailPanelDataCache],
);
Expand Down
24 changes: 12 additions & 12 deletions docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import {
randomTraderName,
randomId,
} from '@mui/x-data-grid-generator';
import { DataGridProps } from '@mui/x-data-grid';
import { DataGridProps, GridRowId } from '@mui/x-data-grid';

const DetailPanelDataCache = React.createContext<Map<string, any>>(new Map());
type Products = Awaited<ReturnType<typeof getProducts>>;

const DetailPanelDataCache = React.createContext(new Map<GridRowId, Products>());

async function getProducts(orderId: Customer['id']) {
await new Promise((resolve) => {
Expand Down Expand Up @@ -48,7 +50,8 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) {
// Store the data in cache so that when detail panel unmounts due to virtualization, the data is not lost
detailPanelDataCache.set(rowProp.id, response);
}
const result = detailPanelDataCache.get(rowProp.id);

const result = detailPanelDataCache.get(rowProp.id)!;

if (!isMounted) {
return;
Expand Down Expand Up @@ -127,21 +130,18 @@ const getDetailPanelContent: DataGridProps['getDetailPanelContent'] = (params) =
const getDetailPanelHeight = () => 240;

export default function LazyLoadingDetailPanel() {
const detailPanelDataCache = React.useRef(new Map()).current;
const detailPanelDataCache = React.useRef(new Map<GridRowId, Products>()).current;

const handleDetailPanelExpansionChange = React.useCallback<
NonNullable<DataGridProProps['onDetailPanelExpandedRowIdsChange']>
>(
(newExpandedRowIds) => {
// Only keep cached data for detail panels that are still expanded
const preservedEntries = newExpandedRowIds.map((id) => [
id,
detailPanelDataCache.get(id),
]);
detailPanelDataCache.clear();
preservedEntries.forEach(
([id, value]) => value && detailPanelDataCache.set(id, value),
);
for (const [id] of detailPanelDataCache) {
if (!newExpandedRowIds.has(id)) {
detailPanelDataCache.delete(id);
}
}
},
[detailPanelDataCache],
);
Expand Down
4 changes: 2 additions & 2 deletions docs/data/data-grid/master-detail/master-detail.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ The following example demonstrates this option in action:

## Controlling expanded detail panels

To control which rows are expanded, pass a list of row IDs to the `detailPanelExpandedRowIds` prop.
To control which rows are expanded, pass a set of row IDs to the `detailPanelExpandedRowIds` prop.
Passing a callback to the `onDetailPanelExpandedRowIds` prop can be used to detect when a row gets expanded or collapsed.

On the other hand, if you only want to initialize the Data Grid with some rows already expanded, use the `initialState` prop as follows:

```tsx
<DataGridPro initialState={{ detailPanel: { expandedRowIds: [1, 2, 3] } }}>
<DataGridPro initialState={{ detailPanel: { expandedRowIds: new Set([1, 2, 3]) } }}>
```

{{"demo": "ControlMasterDetail.js", "bg": "inline", "defaultCodeOpen": false}}
Expand Down
24 changes: 15 additions & 9 deletions docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,23 @@ function CustomDetailPanelHeader() {
gridDetailPanelExpandedRowsContentCacheSelector,
);

const noDetailPanelsOpen = expandedRowIds.length === 0;
const noDetailPanelsOpen = expandedRowIds.size === 0;

const expandOrCollapseAll = () => {
const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
const allRowIdsWithDetailPanels = Object.keys(rowsWithDetailPanels).map((key) =>
apiRef.current.getRowId(dataRowIdToModelLookup[key]),
);

apiRef.current.setExpandedDetailPanels(
noDetailPanelsOpen ? allRowIdsWithDetailPanels : [],
);
if (noDetailPanelsOpen) {
const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
const allRowIdsWithDetailPanels = new Set();
for (const key in rowsWithDetailPanels) {
if (rowsWithDetailPanels.hasOwnProperty(key)) {
allRowIdsWithDetailPanels.add(
apiRef.current.getRowId(dataRowIdToModelLookup[key]),
);
}
}
apiRef.current.setExpandedDetailPanels(allRowIdsWithDetailPanels);
} else {
apiRef.current.setExpandedDetailPanels(new Set());
}
};

const Icon = noDetailPanelsOpen ? UnfoldMoreIcon : UnfoldLessIcon;
Expand Down
24 changes: 15 additions & 9 deletions docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,23 @@ function CustomDetailPanelHeader() {
gridDetailPanelExpandedRowsContentCacheSelector,
);

const noDetailPanelsOpen = expandedRowIds.length === 0;
const noDetailPanelsOpen = expandedRowIds.size === 0;

const expandOrCollapseAll = () => {
const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
const allRowIdsWithDetailPanels: GridRowId[] = Object.keys(
rowsWithDetailPanels,
).map((key) => apiRef.current.getRowId(dataRowIdToModelLookup[key]));

apiRef.current.setExpandedDetailPanels(
noDetailPanelsOpen ? allRowIdsWithDetailPanels : [],
);
if (noDetailPanelsOpen) {
const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
const allRowIdsWithDetailPanels = new Set<GridRowId>();
for (const key in rowsWithDetailPanels) {
if (rowsWithDetailPanels.hasOwnProperty(key)) {
allRowIdsWithDetailPanels.add(
apiRef.current.getRowId(dataRowIdToModelLookup[key]),
);
}
}
apiRef.current.setExpandedDetailPanels(allRowIdsWithDetailPanels);
} else {
apiRef.current.setExpandedDetailPanels(new Set());
}
};

const Icon = noDetailPanelsOpen ? UnfoldMoreIcon : UnfoldLessIcon;
Expand Down
12 changes: 8 additions & 4 deletions docs/data/data-grid/row-recipes/DetailPanelOneExpandedRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ const getDetailPanelHeight = () => 50;

export default function DetailPanelOneExpandedRow() {
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState(
[],
() => new Set(),
);

const handleDetailPanelExpandedRowIdsChange = React.useCallback((newIds) => {
setDetailPanelExpandedRowIds(
newIds.length > 1 ? [newIds[newIds.length - 1]] : newIds,
);
if (newIds.size > 1) {
const newSet = new Set();
const newIdsArray = Array.from(newIds);
newSet.add(newIdsArray[newIdsArray.length - 1]);
} else {
setDetailPanelExpandedRowIds(newIds);
}
}, []);

return (
Expand Down
25 changes: 14 additions & 11 deletions docs/data/data-grid/row-recipes/DetailPanelOneExpandedRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,22 @@ const getDetailPanelContent: DataGridProProps['getDetailPanelContent'] = ({
const getDetailPanelHeight: DataGridProProps['getDetailPanelHeight'] = () => 50;

export default function DetailPanelOneExpandedRow() {
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState<
GridRowId[]
>([]);

const handleDetailPanelExpandedRowIdsChange = React.useCallback(
(newIds: GridRowId[]) => {
setDetailPanelExpandedRowIds(
newIds.length > 1 ? [newIds[newIds.length - 1]] : newIds,
);
},
[],
const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = React.useState(
() => new Set<GridRowId>(),
);

const handleDetailPanelExpandedRowIdsChange = React.useCallback<
NonNullable<DataGridProProps['onDetailPanelExpandedRowIdsChange']>
>((newIds) => {
if (newIds.size > 1) {
const newSet = new Set();
const newIdsArray = Array.from(newIds);
newSet.add(newIdsArray[newIdsArray.length - 1]);
} else {
setDetailPanelExpandedRowIds(newIds);
}
}, []);

return (
<Box sx={{ height: 400, width: '100%' }}>
<DataGridPro
Expand Down
4 changes: 1 addition & 3 deletions docs/pages/x/api/data-grid/data-grid-premium.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@
},
"default": "\"standard\""
},
"detailPanelExpandedRowIds": {
"type": { "name": "arrayOf", "description": "Array&lt;number<br>&#124;&nbsp;string&gt;" }
},
"detailPanelExpandedRowIds": { "type": { "name": "instanceOf", "description": "Set" } },
"disableAggregation": { "type": { "name": "bool" }, "default": "false" },
"disableAutosize": { "type": { "name": "bool" }, "default": "false" },
"disableChildrenFiltering": { "type": { "name": "bool" }, "default": "false" },
Expand Down
4 changes: 1 addition & 3 deletions docs/pages/x/api/data-grid/data-grid-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@
},
"default": "\"standard\""
},
"detailPanelExpandedRowIds": {
"type": { "name": "arrayOf", "description": "Array&lt;number<br>&#124;&nbsp;string&gt;" }
},
"detailPanelExpandedRowIds": { "type": { "name": "instanceOf", "description": "Set" } },
"disableAutosize": { "type": { "name": "bool" }, "default": "false" },
"disableChildrenFiltering": { "type": { "name": "bool" }, "default": "false" },
"disableChildrenSorting": { "type": { "name": "bool" }, "default": "false" },
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/x/api/data-grid/grid-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"isPremiumPlan": true
},
"getExpandedDetailPanels": {
"type": { "description": "() =&gt; GridRowId[]" },
"type": { "description": "() =&gt; Set&lt;GridRowId&gt;" },
"required": true,
"isProPlan": true
},
Expand Down Expand Up @@ -335,7 +335,7 @@
"required": true
},
"setExpandedDetailPanels": {
"type": { "description": "(ids: GridRowId[]) =&gt; void" },
"type": { "description": "(ids: Set&lt;GridRowId&gt;) =&gt; void" },
"required": true,
"isProPlan": true
},
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/x/api/data-grid/grid-detail-panel-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
{
"name": "getExpandedDetailPanels",
"description": "Returns the rows whose detail panel is open.",
"type": "() => GridRowId[]"
"type": "() => Set<GridRowId>"
},
{
"name": "setExpandedDetailPanels",
"description": "Changes which rows to expand the detail panel.",
"type": "(ids: GridRowId[]) => void"
"type": "(ids: Set<GridRowId>) => void"
},
{
"name": "toggleDetailPanel",
Expand Down
8 changes: 1 addition & 7 deletions docs/pages/x/api/data-grid/selectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
},
{
"name": "gridDetailPanelExpandedRowIdsSelector",
"returnType": "GridRowId[]",
"returnType": "Set<GridRowId>",
"description": "",
"supportsApiRef": false
},
Expand All @@ -140,12 +140,6 @@
"description": "",
"supportsApiRef": false
},
{
"name": "gridDetailPanelExpandedRowsHeightCacheSelector",
"returnType": "Record<GridRowId, number>",
"description": "",
"supportsApiRef": true
},
{
"name": "gridDimensionsSelector",
"returnType": "GridDimensions",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,7 @@ DataGridPremiumRaw.propTypes = {
/**
* The row ids to show the detail panel.
*/
detailPanelExpandedRowIds: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
),
detailPanelExpandedRowIds: PropTypes /* @typescript-to-proptypes-ignore */.instanceOf(Set),
/**
* If `true`, aggregation is disabled.
* @default false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ function ApiRefPrivateMethods() {
apiRef.current.applyStrategyProcessor;
// @ts-expect-error Property 'storeDetailPanelHeight' does not exist on type 'GridApiPremium'
apiRef.current.storeDetailPanelHeight;
// @ts-expect-error Property 'detailPanelHasAutoHeight' does not exist on type 'GridApiPremium'
apiRef.current.detailPanelHasAutoHeight;
// @ts-expect-error Property 'calculateColSpan' does not exist on type 'GridApiPremium'
apiRef.current.calculateColSpan;
// @ts-expect-error Property 'rowHasAutoHeight' does not exist on type 'GridApiPremium'
Expand Down
4 changes: 1 addition & 3 deletions packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,7 @@ DataGridProRaw.propTypes = {
/**
* The row ids to show the detail panel.
*/
detailPanelExpandedRowIds: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
),
detailPanelExpandedRowIds: PropTypes /* @typescript-to-proptypes-ignore */.instanceOf(Set),
/**
* If `true`, column autosizing on header separator double-click is disabled.
* @default false
Expand Down
Loading

0 comments on commit 45e01cf

Please sign in to comment.