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

[DataGridPro] Use Set for detailPanelExpandedRowIds #15835

Merged
merged 17 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
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
Loading