-
-
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
[DataGrid] Data source with editing #16045
base: master
Are you sure you want to change the base?
Conversation
Deploy preview: https://deploy-preview-16045--material-ui-x.netlify.app/ Updated pages: |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
packages/x-data-grid/src/hooks/features/dataSource/gridDataSourceError.ts
Outdated
Show resolved
Hide resolved
packages/x-data-grid/src/hooks/features/editing/useGridRowEditing.ts
Outdated
Show resolved
Hide resolved
packages/x-data-grid/src/hooks/features/dataSource/gridDataSourceError.ts
Outdated
Show resolved
Hide resolved
return; | ||
} | ||
updatedRows[rowIndex] = rowUpdate; | ||
cache.set(getRowsParams, { ...cachedData, rows: updatedRows }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is way more complicated than this 😬
This only works if sorting and/or filtering is not applied. Otherwise, you need to have this row in some other place or not in this cache key at all anymore. Not only that, but it affects other cache keys as well.
I am not event sure if we can do anything to keep the cache once sort/filter is there unless we don't change the current cache structure completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A composite key may be?
Instead of 'row.id' only, we create a key for all the differentiating factors e.g.
const key = JSON.stringify([row.id, filterModel, sortModel, groupKeys])
const value = getRowParams
Then, when searching for a specific row, we generate that composite key again based on the current model values.
I'll give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is the position
If you sort by certain column and you change the value of that column, you need to update all chunks in between and move one record up and then inject updated record in the chunk which holds the position that the new value occupies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on how complex you want to go I see two possibilities with the current cache structure.
- You only keep cache chunks with the pagination param only (since it doesn't affect position or other data) and clear all others
- You track which columns have changed and you update all cache chunks that have sort/filter/group/aggregation params that are not related to the updated columns and clear the rest
As mentioned above, updating cache for the columns that are updated is pretty hard. Problem mentioned for sorting applies for other operations that we cache - you need new aggregation amount or you need to remove the row completely for some filter param because it becomes filtered out (which means you have to adjust some other chunks related to that filter param), etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You track which columns have changed and you update all cache chunks that have sort/filter/group/aggregation params that are not related to the updated columns and clear the rest
@arminmeh You made some great points. I agree that delving deeper into this approach could be highly complex and performance-intensive. More importantly, Data Grid cache should not handle business logic owned by the server, such as server-side sorting, especially since it also lacks access to all the data.
If we extract the models which might affect the visibility or positioning of rows when an edit is made, they would be:
Model | Reasoning |
---|---|
sortModel |
Determines row positions; an edit might cause a row to move, requiring a refetch to maintain correct order. The edited row could literally be anywhere, even in the un-fetched chunks. |
filterModel |
Controls row visibility; an edited row may no longer match the filter criteria and needs to be removed or added dynamically. |
aggregationModel |
Affects aggregated values; editing a row could change totals, averages, or other computed metrics, necessitating a refresh. |
If any of these models are active, the Data Grid cannot accurately determine the edited row’s position (or what other rows will be impacted with this change) without access to server-side business logic and data, which it does not have. Additionally, it cannot predict which row, if any, should replace a removed one in the current chunk.
The best option I see here is a hybrid approach where we partially reap the benefits of caching with editing.
-
✅ On every edit operation, if no sorting, filtering, or aggregation is active → Mutate cache entry
The users fully enjoy the client-side caching benefits in this case -
❌ On every edit operation, if any of those models are active → Invalidate cache and refetch the current viewport
This case would be one of the limitations of the client-side cache, i.e. as soon as an edit is made, the cache has to be cleared. -
💡 As an alternative, we could urge the users to consider server-side caching in cases where editing has to be used with one or more of sorting, filtering, and aggregation models, since the server has access to all the data and could provide a more reliable caching.
Lmk how you feel about this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our cache entries are separated by the sort/filter/aggregation model states so I think that the options that you have listed should always be applied to the entries for those states regardless of the current active state.
So this
✅ On every edit operation, if no sorting, filtering, or aggregation is active → Mutate cache entry
The users fully enjoy the client-side caching benefits in this case❌ On every edit operation, if any of those models are active → Invalidate cache and refetch the current viewport
This case would be one of the limitations of the client-side cache, i.e. as soon as an edit is made, the cache has to be cleared.
Becomes
On every edit operation → Mutate cache entries without sorting, filtering, or aggregation params in the key and remove other cache entries.
I am not sure if refetch the current viewport
is needed. If you don't do it, current page is potentially not cached, but it will be cached next time.
Maybe you will not get to it anymore at all, which will save one request if you don't refetch automatically.
💡 As an alternative, we could urge the users to consider server-side caching in cases where editing has to be used with one or more of sorting, filtering, and aggregation models, since the server has access to all the data and could provide a more reliable caching.
Agree - and pointing to the section with the custom cache feature.
@@ -125,6 +132,9 @@ export const useGridDataSourceBase = <Api extends GridPrivateApiCommunity>( | |||
const cacheResponses = cacheChunkManager.splitResponse(fetchParams, getRowsResponse); | |||
cacheResponses.forEach((response, key) => { | |||
cache.set(key, response); | |||
response.rows.forEach((row) => { | |||
rowIdToGetRowsParams.current[row.id] = fetchParams; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one row will be present in multiple cache keys when sorting/filtering/grouping is applied
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linked with #16045 (comment), this dictionary will only be used if no such model is active which alters rows' positions or visibility.
Co-authored-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> Signed-off-by: Bilal Shafi <bilalshafidev@gmail.com>
Resolves #13261
Preview
In progress items:
useMockServer
Future improvements:
rowIdToGetRowsParams
touseTransition
or similar delayed computation mechanism (Should we ?)