mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.12k stars 1.28k forks source link

When i try to give the chekcboxSelectionn a default value, React is throwing the error: Cannot update a component (`ControlledSelectionGrid`) while rendering a different component (`ForwardRef(DataGrid)`). To locate the bad setState()... #9805

Open john1625b opened 1 year ago

john1625b commented 1 year ago

Duplicates

Latest version

Steps to reproduce πŸ•Ή

https://codesandbox.io/s/hardcore-bhaskara-kc9n67?file=/demo.tsx

In that above example, see that I have given the rowSelectionModel a default value. The id that represents "Oats":

const [rowSelectionModel, setRowSelectionModel] = React.useState<
    GridRowSelectionModel
  >(["f3577f2b-6a11-508e-9696-e2760d7dcd9f"]);

But its throwing the error in the console:

Warning: Cannot update a component (`ControlledSelectionGrid`) while rendering a different component (`ForwardRef(DataGrid)`). To locate the bad setState() call inside `ForwardRef(DataGrid)`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
DataGrid@https://kc9n67.csb.app/node_modules/@mui/x-data-grid/DataGrid/DataGrid.js:21:62
div
ControlledSelectionGrid@https://kc9n67.csb.app/demo.tsx:19:43
StyledEngineProvider@https://kc9n67.csb.app/node_modules/@mui/styled-engine/StyledEngineProvider/StyledEngineProvider.js:21:58

Current behavior 😯

No response

Expected behavior πŸ€”

No response

Context πŸ”¦

No response

Your environment 🌎

npx @mui/envinfo System: OS: macOS 13.5 Binaries: Node: 18.16.1 - ~/.nvm/versions/node/v18.16.1/bin/node Yarn: 1.22.18 - /opt/homebrew/bin/yarn npm: 9.5.1 - ~/.nvm/versions/node/v18.16.1/bin/npm Browsers: Chrome: 114.0.5735.248 Edge: Not Found Safari: 16.6 npmPackages: @emotion/react: ^11.10.4 => 11.11.1 @emotion/styled: ^11.10.4 => 11.11.0 @mui/base: 5.0.0-alpha.98 @mui/core-downloads-tracker: 5.14.1 @mui/icons-material: ^5.10.6 => 5.14.1 @mui/lab: 5.0.0-alpha.100 => 5.0.0-alpha.100 @mui/material: ^5.10.6 => 5.14.1 @mui/private-theming: 5.13.7 @mui/styled-engine: 5.13.2 @mui/system: ^5.10.6 => 5.14.1 @mui/types: 7.2.4 @mui/utils: ^5.10.6 => 5.14.1 @mui/x-data-grid: 6.10.0 @mui/x-data-grid-pro: ^6.10.0 => 6.10.0 @mui/x-license-pro: 6.10.0 @types/react: ^18.0.21 => 18.2.15 react: ^18.2.0 => 18.2.0 react-dom: ^18.2.0 => 18.2.0 typescript: ^5.1.6 => 5.1.6

Order ID or Support key πŸ’³ (optional)

61801

m4theushw commented 1 year ago

This error occurs because we have a special logic to remove, from the specified selection model, those rows that are not in the rows prop. This logic, in the first render, is triggered during the render phrase because it listens to the sortedRowsSet event.

https://github.com/mui/mui-x/blob/bb73767b6eb89d9f6af79634f512bdf6671f98ba/packages/grid/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts#L319-L340

I tried to fix below this error by not updating the state during the render phase. It's not very elegant because it relays on an effect.

diff --git a/packages/grid/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts b/packages/grid/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts
index baa86964e..5babb09d3 100644
--- a/packages/grid/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts
+++ b/packages/grid/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts
@@ -526,11 +526,17 @@ export const useGridRowSelection = (
     [apiRef, handleSingleRowSelection, selectRows, visibleRows.rows, canHaveMultipleSelection],
   );

-  useGridApiEventHandler(
-    apiRef,
-    'sortedRowsSet',
-    runIfRowSelectionIsEnabled(removeOutdatedSelection),
-  );
+  const [sortedRowsSet, setSortedRowsSet] = React.useState([]);
+
+  const handleSortedRowsSet = React.useCallback((sortedRows) => {
+    setSortedRowsSet(sortedRows);
+  }, []);
+
+  React.useEffect(() => {
+    removeOutdatedSelection();
+  }, [sortedRowsSet, removeOutdatedSelection]);
+
+  useGridApiEventHandler(apiRef, 'sortedRowsSet', runIfRowSelectionIsEnabled(handleSortedRowsSet));
   useGridApiEventHandler(apiRef, 'rowClick', runIfRowSelectionIsEnabled(handleRowClick));
   useGridApiEventHandler(
     apiRef,
diff --git a/packages/grid/x-data-grid/src/hooks/features/sorting/useGridSorting.ts b/packages/grid/x-data-grid/src/hooks/features/sorting/useGridSorting.ts
index a5847ddb7..f55a4c1ef 100644
--- a/packages/grid/x-data-grid/src/hooks/features/sorting/useGridSorting.ts
+++ b/packages/grid/x-data-grid/src/hooks/features/sorting/useGridSorting.ts
@@ -166,7 +166,7 @@ export const useGridSorting = (
       };
     });

-    apiRef.current.publishEvent('sortedRowsSet');
+    apiRef.current.publishEvent('sortedRowsSet', apiRef.current.state.sorting.sortedRows);
     apiRef.current.forceUpdate();
   }, [apiRef, logger, props.sortingMode]);

A workaround for now is to enable the keepNonExistentRowsSelected prop. The drawback is that the selected row count in the footer will include non-existent rows.

john1625b commented 1 year ago

ok keepNonExistentRowsSelected works for me as an interim solution. I don't think I'll close the issue since there's still work to be done.