Skip to content
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] Fix scroll jumping #14929

Merged
merged 24 commits into from
Oct 16, 2024
Merged

[DataGrid] Fix scroll jumping #14929

merged 24 commits into from
Oct 16, 2024

Conversation

romgrk
Copy link
Contributor

@romgrk romgrk commented Oct 12, 2024

@romgrk romgrk added the component: data grid This is the name of the generic UI component, not the React module! label Oct 12, 2024
@mui-bot
Copy link

mui-bot commented Oct 12, 2024

Deploy preview: https://deploy-preview-14929--material-ui-x.netlify.app/

Generated by 🚫 dangerJS against f8468bd

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I'm fixing/refactoring the 'auto' height code, I'm seeing stuff that could be removed. I see that there is a .resized flag that is never used, except in unstable_setRowHeight which is itself not used afaict. It was added in #3751. @cherniavskii, can we remove this method and its associated data?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a programmatic API that developers can use. I'm not sure if it's actually being used though, it could be useful for implementing row resizing.
I prefer keeping it if it's not causing issues.

Copy link
Contributor Author

@romgrk romgrk Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like much keeping code that's unused, it makes reading & understanding the rest of the file more tedious. For example, the isResized condition increases the cyclomatic complexity of the calculateRowProcessedSizes function.

But should we consider removing the unstable_ prefix from those methods, if we're going to keep them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that the unstable_setRowHeight method is marked as @ignore - do not document in addition to unstable_, thus why I suggested removing it.

Copy link
Member

@cherniavskii cherniavskii Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unstable_setRowHeight method is marked as @ignore - do not document

Fair enough, then I'm OK with removing it 👍🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think deleting code is my favourite part of programming.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about fixing a regression caused by a deleted code 😆

@romgrk romgrk marked this pull request as ready for review October 15, 2024 21:46
Comment on lines +222 to +238
const resizeObserver = useLazyRef(
() =>
new ResizeObserver((entries) => {
for (let i = 0; i < entries.length; i += 1) {
const entry = entries[i];
const height =
entry.borderBoxSize && entry.borderBoxSize.length > 0
? entry.borderBoxSize[0].blockSize
: entry.contentRect.height;
const rowId = (entry.target as any).__mui_id;
apiRef.current.unstable_storeRowHeightMeasurement(rowId, height);
}
if (!isHeightMetaValid.current) {
apiRef.current.requestPipeProcessorsApplication('rowHeight');
}
}),
).current;
Copy link
Contributor Author

@romgrk romgrk Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this here because ResizeObserver was designed to be one-listener-many-elements, the performance cost of using one per element is illustrated by the chromium authors here.

This also simplifies the logic as the N resize notifications come at once, so the whole debounce logic is not needed anymore. Debounce was the problem with scroll jumping. We had the data to avoid jumps, but we weren't using it because the debounce was keeping the invalidated data in use.

@romgrk romgrk requested a review from a team October 16, 2024 02:41
Comment on lines +91 to +93
// HACK: rowHeight trails behind the most up-to-date value just enough to
// mess the initial rowsMeta hydration :/
const baseRowHeight = gridDimensionsSelector(apiRef.current.state).rowHeight;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cherniavskii The recent change you made to pull rowHeight from useGridSelector coupled with the changes of this PR created this issue :| It's a symptom of this.

Comment on lines -269 to +221
rowsHeightLookup.current = {};
const resetRowHeights: GridRowsMetaApi['resetRowHeights'] = () => {
heightCache.clear();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used Object.create(null) when creating the lookup but not when resetting it here. Using Map for lookups avoids the issues with {} (prototype injection, and presence of Object methods), and is also more performant.

Comment on lines -17 to +18
React.useEffect(() => {
useEnhancedEffect(() => {
Copy link
Contributor Author

@romgrk romgrk Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was causing subtle bugs, because some of our hook effects use useEnhancedEffect (aka React.useLayoutEffect), they were running before the API methods were updated, so they were calling outdated useCallback instances.

@romgrk
Copy link
Contributor Author

romgrk commented Oct 16, 2024

The argos changes all look positive to me, they show the grid reacting to 'auto' height faster.

Copy link
Contributor Author

@romgrk romgrk Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sidenote but the detail panels code is terribly unefficient. IIUC, it calls getDetailPanel(Height|Content) for all the rows of the grid, regardless if they're displayed or not. For large datasets, the performance must be horrible.

Copy link
Contributor

@KenanYusuf KenanYusuf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactors 👍

Tested the scrolling issue with getRowHeight: () => 'auto' and I could no longer reproduce it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module!
Projects
None yet
5 participants