mui-x icon indicating copy to clipboard operation
mui-x copied to clipboard

[data grid] Unexpected Application Error in GridDetailPanelToggleCell

Open conerye opened this issue 1 year ago • 14 comments

The problem in depth

We are getting ready to release the latest version of our application... Testing the production build, we are seeing an Unexpected Application Error in GridDetailPanelToggleCell and we are not sure how to determine what is causing this issue. It only occurs on production build, not in our development environment... It occurs on a page with a table that has row details panel, but not all rows have data in the details panel (so some rows will show with a disabled expand icon). Error is as follows:

TypeError: Cannot read properties of undefined (reading '2') at h (GridDetailPanelToggleCell.js:34:56) at wa (react-dom.production.min.js:167:137) at wl (react-dom.production.min.js:290:337) at vc (react-dom.production.min.js:280:389) at mc (react-dom.production.min.js:280:320) at Cc (react-dom.production.min.js:280:180) at ac (react-dom.production.min.js:271:88) at ic (react-dom.production.min.js:268:429) at y (scheduler.production.min.js:13:203) at MessagePort._ (scheduler.production.min.js:14:128)

Lines 33-34 of GridDetailPanelToggleCell.js: const contentCache = useGridSelector(apiRef, gridDetailPanelExpandedRowsContentCacheSelector); const hasContent = /*#__PURE__*/React.isValidElement(contentCache[id]

contentCache is undefined and then trying to access the data associated with the specified id is causing an application error.

We are using a table that some entries have an expanding detail panel and some do not. That doesn’t seem to be the issue, when the contentCache object exists, there is null data associated with some ids and others have data corresponding to their detail panel, and there are no errors retrieving the null data and disabling the expansion panel arrow. This happens when the page initially loads and happens very quickly as the page is loading. Refreshing the page would often cause an application error, stating that we are trying to read properties of undefined on line 34 of GridDetailPanelToggleCell. I put a breakpoint and could see that contentCache was undefined when this error was being thrown.

Saw issues with simply refreshing the page on the following browsers. The page loads very quickly. This happened about every 3-4 refreshes: Chrome 122.0.6261.112 Edge 122.0.2365.80

Could not replicate by simply refreshing, but I had right clicked and opened a right click menu and then refreshed and saw a similar error on the same line. I couldn’t get this one to happen as much as the previous: Firefox 115.8.0

Some more details in addition...there have been times where I load the page and the detail panel expansion arrow is not there even when it should be and clicking the row and results in the same app error...

Seems like a timing thing??? Thoughts on how we can get more info and resolve this issue?

Your environment

`npx @mui/envinfo`
  System:
    OS: Windows 10 10.0.19045
  Binaries:
    Node: 16.15.0 - C:\Program Files\nodejs\node.EXE
    npm: 8.5.5 - C:\Program Files\nodejs\npm.CMD
    pnpm: Not Found
  Browsers:
    Chrome: Not Found
    Edge: Chromium (123.0.2420.81)
  npmPackages:
    @emotion/react: 11.11.1 => 11.11.1
    @emotion/styled: 11.11.0 => 11.11.0
    @mui/base:  5.0.0-beta.40
    @mui/core-downloads-tracker:  5.15.14
    @mui/icons-material: 5.14.6 => 5.14.6
    @mui/material: 5.14.6 => 5.14.6
    @mui/private-theming:  5.15.14
    @mui/styled-engine:  5.15.14
    @mui/system: 5.14.6 => 5.14.6
    @mui/types:  7.2.14
    @mui/utils:  5.15.14
    @mui/x-data-grid:  6.12.0
    @mui/x-data-grid-premium: 6.12.0 => 6.12.0
    @mui/x-data-grid-pro:  6.12.0
    @mui/x-date-pickers:  6.12.0
    @mui/x-date-pickers-pro: 6.12.0 => 6.12.0
    @mui/x-license-pro: 6.10.2 => 6.10.2
    @types/react:  18.0.14
    react: 18.2.0 => 18.2.0
    react-dom: 18.2.0 => 18.2.0
    typescript:  4.7.4

Search keywords: 'Unexpected Application Error' GridDetailPanelToggleCell Order ID: 331993142

conerye avatar Apr 11 '24 17:04 conerye

Hi @conerye This looks like a race condition. Can you try upgrading the Data Grid to the latest v6 release? Can you still reproduce the issue?

cherniavskii avatar Apr 12 '24 13:04 cherniavskii

Also, could you create a demo that would mimic your Data Grid setup? Thanks!

cherniavskii avatar Apr 12 '24 13:04 cherniavskii

I upgraded to version 6.19.9 and tried this scenario on our test environment again... Now every time I refresh there's no option for a detail panel expansion and clicking the row gives an app error. I was seeing this occasionally before but it's on every refresh post upgrade.

conerye avatar Apr 12 '24 22:04 conerye

We tried to create a demo... The issue doesn't show in codesandbox though, probably for the same reason it doesn't show in our development environment; it only shows with a production build/on our test machines. But here is the codesandbox that was created from altering the MUI demo code sandbox for the detail panel: https://codesandbox.io/p/sandbox/competent-breeze-w4pr2z?file=%2Fsrc%2FDemo.js%3A73%2C12

It is a simple example to show what we are trying to do... in our scenario, if there is none of a particular type of item in the list, then we do not want to show the column for the expansion panel - shown in the demo as a check for a particular name: getDetailPanelContent={hasName ? getDetailPanelContent : null} so the value for the getDetailPanelContent prop is null if there are none of a particular item in the list...

Is there is different/recommended way to do this?

conerye avatar Apr 12 '24 22:04 conerye

The way you pass in the getter function is slightly incorrect. The function has to be called on every row, so you would be returning your detail panel.

Try refactoring to include the check and return null if the check fails:

const getDetailPanelContent = React.useCallback(
  ({ row }) => {
    if (row.customer === "Matheus") return null
    return <DetailPanelContent row={row} />
  },
  [],
);

... in the data grid props:

<DataGridPro
  columns={columns}
  rows={rows}
  getDetailPanelHeight={getDetailPanelHeight}
  getDetailPanelContent={getDetailPanelContent}
/>

That way you can ensure that the function is always callable and returns the desired result. Like this the button is also disabled when no content is available.

Does that work for you?

michelengelen avatar Apr 15 '24 13:04 michelengelen

@conerye

here is the codesandbox that was created from altering the MUI demo code sandbox for the detail panel: codesandbox.io/p/sandbox/competent-breeze-w4pr2z?file=%2Fsrc%2FDemo.js%3A73%2C12

I downloaded the sandbox and ran it locally in production mode (npm run build && npx server -s build) – I can't reproduce the issue. Is the setup close to what you do? Do you also render a data grid inside the detail panel?

cherniavskii avatar Apr 15 '24 15:04 cherniavskii

Changing our code, as michelengelen suggested, so that getDetailPanelContent always has a callable function and then refactoring the function to include the check and return null if the check fails, does work and we are not able to reproduce the Unexpected Application error with the code this way. The difference is that now the detail panel expansion column shows even when there are no rows in the table that meet the criteria for the detail panel expansion -> all rows have the expansion icon disabled. So, the Unexpected Application problem is resolved, BUT we would like to know if there is a way to hide the detail panel expansion column in this scenario (no rows will ever have the detail panel)?

conerye avatar Apr 15 '24 19:04 conerye

@conerye ... you would need to have an additional check for that: Basically the same as before, but when the condition is falsey the value for getDetailPanelContent needs to be null/undefined:

const needsDetailPanel = rows.some((row) => row.customer === 'Michel');

return (
  <Box sx={{ width: '100%', height: 400 }}>
    <DataGridPro
      columns={columns}
      rows={rows}
      getDetailPanelHeight={getDetailPanelHeight}
      getDetailPanelContent={needsDetailPanel ? getDetailPanelContent : undefined}
    />
  </Box>
);

That way the grid will know that there is not detail panel and does not render the toggle

michelengelen avatar Apr 16 '24 09:04 michelengelen

will give that a try with undefined and report back. but originally we were doing exactly that but with null and it was stated above that it was the cause of this error. Why would undefined work when null does not??? thanks!

conerye avatar Apr 17 '24 20:04 conerye

will give that a try with undefined and report back. but originally we were doing exactly that but with null and it was stated above that it was the cause of this error. Why would undefined work when null does not??? thanks!

I think there might be a slight misunderstanding here: Passing undefined or null will disable the feature and show no toggle column, but your example was always truethy due to const hasName = rows.some((row) => row.customer !== 'Matheus');, so the rendering function did get passed in any situation.

The condition hasName ? getDetailPanelContent : null is only run once on render and not for every row.

The problem was that the rendering function was running into an error because the logic to return null if row.customer === 'Matheus' was sitting inside the DetailPanelContent component. The wrapper was basically the problem.

Is it clearer now?


BTW: Did you get the chance to try the solution already?

michelengelen avatar Apr 18 '24 08:04 michelengelen

I’m a little confused... we know that the condition is only run once per render. That condition is used to determine if the expansion arrow column should be visible at all, not to determine the content of the detail panel. The condition looks at all the rows to determine if the column should show and then when getting the detail panel content, it is only looking at the content of that one row. If the data did not have a row with customer === 'Matheus' then the toggle column should not be shown. Using undefined vs null made no difference; both result in the Unexpected Application error when there is data such that the toggle column should not be shown.

conerye avatar Apr 24 '24 20:04 conerye

@conerye I did update the example showing 2 different approaches: Example

The first data grid renders the toggle column because there are no rows that have a total above 1500.

The other one shows that the toggle column will be rendered when there is a row that has a total of more than 1500. Additionally it will disable the toggle for details where there is no customer name in the row data.

Is this what you were looking for?

michelengelen avatar Apr 25 '24 08:04 michelengelen

did you have the link to the right codesandbox? i am just seeing the original one that I posted?

conerye avatar Apr 25 '24 15:04 conerye

sry @conerye ... codesandbox sometimes behaves strange when trying to share from the menu. Here is the updated Example

michelengelen avatar Apr 26 '24 10:04 michelengelen

The issue has been inactive for 7 days and has been automatically closed.

github-actions[bot] avatar May 03 '24 15:05 github-actions[bot]