Skip to content

Commit

Permalink
[DataGrid] Add a recipe to persist column width and order (mui#14560)
Browse files Browse the repository at this point in the history
  • Loading branch information
MBilalShafi committed Nov 7, 2024
1 parent d275788 commit 8b2ba8b
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import {
DataGridPro,
useGridApiRef,
gridColumnFieldsSelector,
} from '@mui/x-data-grid-pro';
import Button from '@mui/material/Button';

const rows = [
{
id: 1,
username: '@MUI',
age: 20,
},
];

export default function ColumnSizingPersistWidthOrder() {
const apiRef = useGridApiRef();
const [index, setIndex] = React.useState(0);
const inputColumns = React.useMemo(
() => [
{ field: 'id' },
{ field: 'username', width: 200, key: index },
{ field: 'age', disableReorder: true },
],
[index],
);

const columnsState = useColumnsState(apiRef, inputColumns);

return (
<div style={{ width: '100%' }}>
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
</div>
);
}

const useColumnsState = (apiRef, columns) => {
const [widths, setWidths] = React.useState({});
const [orderedFields, setOrderedFields] = React.useState(() =>
columns.map((column) => column.field),
);

const onColumnWidthChange = React.useCallback(
({ colDef, width }) => {
setWidths((prev) => ({ ...prev, [colDef.field]: width }));
},
[setWidths],
);

const onColumnOrderChange = React.useCallback(() => {
setOrderedFields(gridColumnFieldsSelector(apiRef));
}, [apiRef, setOrderedFields]);

const computedColumns = React.useMemo(
() =>
orderedFields.reduce((acc, field) => {
const column = columns.find((col) => col.field === field);
if (!column) {
return acc;
}
if (widths[field]) {
acc.push({
...column,
width: widths[field],
});
return acc;
}
acc.push(column);
return acc;
}, []),
[columns, widths, orderedFields],
);

return { columns: computedColumns, onColumnWidthChange, onColumnOrderChange };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from 'react';
import {
DataGridPro,
useGridApiRef,
GridColDef,
GridColumnResizeParams,
gridColumnFieldsSelector,
GridApiPro,
} from '@mui/x-data-grid-pro';
import Button from '@mui/material/Button';

const rows = [
{
id: 1,
username: '@MUI',
age: 20,
},
];

export default function ColumnSizingPersistWidthOrder() {
const apiRef = useGridApiRef();
const [index, setIndex] = React.useState(0);
const inputColumns = React.useMemo(
() => [
{ field: 'id' },
{ field: 'username', width: 200, key: index },
{ field: 'age', disableReorder: true },
],
[index],
);

const columnsState = useColumnsState(apiRef, inputColumns);

return (
<div style={{ width: '100%' }}>
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
</div>
);
}

const useColumnsState = (
apiRef: React.MutableRefObject<GridApiPro>,
columns: GridColDef[],
) => {
const [widths, setWidths] = React.useState<Record<GridColDef['field'], number>>(
{},
);
const [orderedFields, setOrderedFields] = React.useState<GridColDef['field'][]>(
() => columns.map((column) => column.field),
);

const onColumnWidthChange = React.useCallback(
({ colDef, width }: GridColumnResizeParams) => {
setWidths((prev) => ({ ...prev, [colDef.field]: width }));
},
[setWidths],
);

const onColumnOrderChange = React.useCallback(() => {
setOrderedFields(gridColumnFieldsSelector(apiRef));
}, [apiRef, setOrderedFields]);

const computedColumns = React.useMemo(
() =>
orderedFields.reduce<GridColDef[]>((acc, field) => {
const column = columns.find((col) => col.field === field);
if (!column) {
return acc;
}
if (widths[field]) {
acc.push({
...column,
width: widths[field],
});
return acc;
}
acc.push(column);
return acc;
}, []),
[columns, widths, orderedFields],
);

return { columns: computedColumns, onColumnWidthChange, onColumnOrderChange };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Button onClick={() => setIndex((prev) => prev + 1)}>
Update columns reference
</Button>
<div style={{ height: 250 }}>
<DataGridPro
apiRef={apiRef}
columns={columnsState.columns}
onColumnWidthChange={columnsState.onColumnWidthChange}
onColumnOrderChange={columnsState.onColumnOrderChange}
rows={rows}
/>
</div>
20 changes: 20 additions & 0 deletions docs/data/data-grid/column-recipes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Data Grid - Column recipes
---

# Data Grid - Column customization recipes

<p class="description">Advanced column customization recipes.</p>

## Persisting column width and order

When the `columns` prop reference is updated, the column width and order is reset to the `colDef.width` and the order of the `colDef` object and any updates will be lost.
This is because the Data Grid considers update of the columns prop as a new set of columns, and the previous state is discarded.

To persist the column width and order when the `columns` prop is updated, consider persisting the state of the columns in the userland.

{{"demo": "ColumnSizingPersistWidthOrder.js", "disableAd": true, "bg": "inline"}}

:::warning
[Column ordering](/x/react-data-grid/column-ordering/) is a Pro feature, to use it you must be on a Pro or Premium plan.
:::
1 change: 1 addition & 0 deletions docs/data/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const pages: MuiPage[] = [
{ pathname: '/x/react-data-grid/column-groups' },
{ pathname: '/x/react-data-grid/column-ordering', plan: 'pro' },
{ pathname: '/x/react-data-grid/column-pinning', plan: 'pro' },
{ pathname: '/x/react-data-grid/column-recipes', title: 'Recipes' },
],
},
{
Expand Down
7 changes: 7 additions & 0 deletions docs/pages/x/react-data-grid/column-recipes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import * as pageProps from 'docsx/data/data-grid/column-recipes/index.md?muiMarkdown';

export default function Page() {
return <MarkdownDocs {...pageProps} />;
}

0 comments on commit 8b2ba8b

Please sign in to comment.