-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
[data grid] Tree data expansion state is lost when data is updated in 6.0.0-beta.1 #7771
Comments
This change was intended (see the first Behavior change of #4927). If the row update is partial, we recommend to use |
Thanks for the quick answer👍Did not spot this when reading the release notes or upgrade guide. But, |
@cherniavskii maybe we could add this behavior change to the migration guide |
@flaviendelangle Indeed, we should include this in the migration guide.
Could you share more details on the motivation behind this behavior change? |
The first reason was that it was not performance-free to check if the old node in the tree was expended or not. And the second one is that now we have two very distinct way of changing the rows:
For me it make sense to push people into using Basically, the way I see it, |
Thanks for the details! |
If you still encounter issues after using the |
Hello, I'm working with DataGridPremium, with collapsable rows (I have a list of items, and I group them by date). When I expand a row, then create a new item in this date, when the state of options is updated, it closes every rows, how would you make them stay open ? |
I understand and agree with the reasoning. However, when using real-time database updates as row data, having the ability to disable this behavior would be useful. Is there a way to turn it off optionally? Considering the size of the app, transitioning to this could take a considerable amount of time. |
Transitioning to using the |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Disregard - this problem was caused by a lack of memoization of the DataGrid when the parent state update was causing re-render. |
Wait a second, so if I have a hassle-free and reasonably cheap way to update whole rows array from server (e.g. on timer) and feed it into DataGrid rows prop - there is no other way to make it keep the expanded/collapsed state between the data updates than the recommended one, which is to handle diffs between old and new data elsewhere via state, refs and such and then notify DataGrid about that via apiRef? And this is by design? Sorry for being bitter but that does not sound user friendly at all. |
@secretwpn No need to handle diffs and state - a single const initialRowsRef = React.useRef(rows);
React.useEffect(() => {
if (rows !== initialRowsRef.current) {
apiRef.current.updateRows(rows);
}
}, [apiRef, rows]); |
@cherniavskii thanks, Andrew, I've tried this but it did not work for me - the expanded state kept resetting I had to go with interface ExpansionState {
[key: GridRowId]: boolean;
} useEffect(() => {
apiRef.current.subscribeEvent('rowExpansionChange', (node) => {
expansionState.current[node.id] = node.childrenExpanded ?? false
})
}, [apiRef])
const isGroupExpanded = useCallback(
(node: GridGroupNode) => expansionState.current[node.id] ?? false,
[expansionState],
) <DataGridPremium
apiRef={apiRef}
isGroupExpandedByDefault={isGroupExpanded}
...
/> as suggested by another comment in one of related discussions #10085 |
This is odd... There's also this detail that you may have missed - along with using <DataGrid
- rows={rows}
+ rows={initialRowsRef.current}
/> This could be the reason why the expanded state kept resetting for you. |
@cherniavskii or @flaviendelangle are there any plans to make
...I'm surprised that updating Right now it seems that the component is treating a change of Any thoughts or insights are appreciated, and thank you for your work! |
It works! By the way, inline function is used in official document. It cost me hours to find this comment, can i get compensation from official? 💢😈 |
To recap this discussion, here is my understanding of the minimal implementation required to support expansion state retention across dataset updates: import type { DataGridPremiumProps, GridValidRowModel } from '@mui/x-data-grid-premium'
import { DataGridPremium, useGridApiRef } from '@mui/x-data-grid-premium'
import { useEffect, useRef } from 'react'
function MyTable(props: DataGridPremiumProps<GridValidRowModel>) {
const { columns, getTreeDataPath, sortingMode, rows, ...dataGridProps } = props
const apiRef = useGridApiRef()
// The table data is stored in a ref so that the exact same reference is passed to the
// `DataGridPremium` component on every render. This ref is never updated. Instead, the
// rows are updated via the `updateRows` method of the `GridApiPremium` instance. This is
// done primarily to avoid auto-collapsing any expanded rows when the table data changes.
const initialData = useRef(rows)
// Wrap `getRowId` in a ref so that it doesn't trigger the `useEffect` below on every render
const getRowIdMemo = useRef(props.getRowId!)
// Handles data updates for the table. When the data changes, the `updateRows` method is called to
// perform an "upsert" of the new data. This is done to avoid auto-collapsing any expanded rows when
// the table data changes. However, by default `updateRows` will not remove any rows that are no
// longer present in the new data. To support removal, we need to merge the new data with the old data
// and add a `_action: 'delete'` property to any rows that are no longer present.
useEffect(() => {
// If we're using server mode, we can't use `updateRows` because the sorting comes out incorrect.
// This happens because the DataGrid expects sorting to be handled externally (on the server), so
// after the upsert occurs it does not re-apply the sort model. Instead we just set the rows
// directly. This means that expansion state will not be preserved for server-side tables.
if (sortingMode === 'server') {
apiRef.current.setRows([...rows])
return
}
// Get the IDs of all current data and identify which are excluded from the new data
const curRows = apiRef.current.getRowModels()
const curIds = curRows.keys()
const newIds = new Set(rows.map(getRowIdMemo.current))
const removeIds = [...curIds].filter((id) => !newIds.has(id))
// Create delete actions for the removed IDs and merge them with the new data
const deleteActions = removeIds.map((id) => ({ ...curRows.get(id), _action: 'delete' as const }))
apiRef.current.updateRows([...rows, ...deleteActions])
}, [apiRef, rows, sortingMode])
// To avoid auto-collapsing of expanded rows, the `getTreeDataPath` prop needs to be the same
// across renders. We wrap it in a ref so that the value provided during the first render is
// used for all subsequent ones.
const getTreeDataPathMemo = useRef(getTreeDataPath)
return (
<DataGridPremium
{...dataGridProps}
apiRef={apiRef}
columns={columns}
getTreeDataPath={getTreeDataPathMemo.current}
rows={initialData.current}
treeData={!!getTreeDataPath}
/>
)
} Without the comments it's about 40 lines of code to implement what I personally feel ought to be the default behavior. There are various gotchas involved:
I'm a big fan of this library and MUI in general, but candidly this API is not very user-friendly. I am happy to provide more information about my use case (though I don't think it's particularly exceptional), and if there are simplifications/corrections to the above please share. |
Hi, thanks for your solution, it's working well. However, it seems not to work with defaultGroupingExpansionDepth. Do you know how to combine both? |
It is working as expected in v5 (and 6.0.0-alpha.0).
Steps to reproduce 🕹
Link to live example: https://codesandbox.io/s/gracious-dream-d69pbp?file=/package.json
Current behavior 😯
The row data is updated but the expansion state is lost (Thomas is closed).
Expected behavior 🤔
The expansion state should be kept when the data is updated. (Thomas should still be expanded and his job title should be updated)
The text was updated successfully, but these errors were encountered: