From 8b2ba8b1e4b44c92c186b4199cb6fc2ba7f22250 Mon Sep 17 00:00:00 2001 From: Bilal Shafi Date: Thu, 7 Nov 2024 08:09:45 +0500 Subject: [PATCH] [DataGrid] Add a recipe to persist column width and order (#14560) --- .../ColumnSizingPersistWidthOrder.js | 87 +++++++++++++++++ .../ColumnSizingPersistWidthOrder.tsx | 95 +++++++++++++++++++ .../ColumnSizingPersistWidthOrder.tsx.preview | 12 +++ docs/data/data-grid/column-recipes/index.md | 20 ++++ docs/data/pages.ts | 1 + .../pages/x/react-data-grid/column-recipes.js | 7 ++ 6 files changed, 222 insertions(+) create mode 100644 docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.js create mode 100644 docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx create mode 100644 docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx.preview create mode 100644 docs/data/data-grid/column-recipes/index.md create mode 100644 docs/pages/x/react-data-grid/column-recipes.js diff --git a/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.js b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.js new file mode 100644 index 000000000000..c1cebe22ca02 --- /dev/null +++ b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.js @@ -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 ( +
+ +
+ +
+
+ ); +} + +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 }; +}; diff --git a/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx new file mode 100644 index 000000000000..a1880f3e7085 --- /dev/null +++ b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx @@ -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 ( +
+ +
+ +
+
+ ); +} + +const useColumnsState = ( + apiRef: React.MutableRefObject, + columns: GridColDef[], +) => { + const [widths, setWidths] = React.useState>( + {}, + ); + const [orderedFields, setOrderedFields] = React.useState( + () => 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((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 }; +}; diff --git a/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx.preview b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx.preview new file mode 100644 index 000000000000..7d13db3ac723 --- /dev/null +++ b/docs/data/data-grid/column-recipes/ColumnSizingPersistWidthOrder.tsx.preview @@ -0,0 +1,12 @@ + +
+ +
\ No newline at end of file diff --git a/docs/data/data-grid/column-recipes/index.md b/docs/data/data-grid/column-recipes/index.md new file mode 100644 index 000000000000..9e4a1eb04587 --- /dev/null +++ b/docs/data/data-grid/column-recipes/index.md @@ -0,0 +1,20 @@ +--- +title: Data Grid - Column recipes +--- + +# Data Grid - Column customization recipes + +

Advanced column customization recipes.

+ +## 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. +::: diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 557be8daaba8..5692afc3f704 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -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' }, ], }, { diff --git a/docs/pages/x/react-data-grid/column-recipes.js b/docs/pages/x/react-data-grid/column-recipes.js new file mode 100644 index 000000000000..8fec3624c430 --- /dev/null +++ b/docs/pages/x/react-data-grid/column-recipes.js @@ -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 ; +}