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

[DataGridPro] Fetch new rows only once when multiple models are changed in one cycle (@arminmeh) #16382

Merged
merged 3 commits into from
Jan 31, 2025

Conversation

arminmeh
Copy link
Contributor

@arminmeh arminmeh commented Jan 29, 2025

Cherry-pick of #16101 and #16395

@arminmeh arminmeh added component: data grid This is the name of the generic UI component, not the React module! plan: Pro Impact at least one Pro user enhancement This is not a bug, nor a new feature cherry-pick The PR was cherry-picked from the newer alpha/beta/stable branch feature: Server integration Better integration with backends, e.g. data source labels Jan 29, 2025
@arminmeh arminmeh requested a review from a team January 29, 2025 12:23
@mui-bot
Copy link

mui-bot commented Jan 29, 2025

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

Generated by 🚫 dangerJS against 23d55dd

@lauri865
Copy link
Contributor

lauri865 commented Jan 29, 2025

Are you sure these tests function properly?

For whatever reason, useMemo is triggered multiple times per test, even with an empty dependency array. So callCount can't be accurate, since it's reset multiple times per test it seems.

Edited dataSourceTreeData.DataGridPro.test.tsx

Moved fetchRowSpy clearing into a hook:

beforeEach(() => {
    console.log('RESET');
    fetchRowsSpy.resetHistory();
});

Added a console.log to useMemo:

const dataSource: GridDataSource = React.useMemo(() => {
      console.log('useMemo');
      // [redacted]
}, []);
```

Tests start failing:
```
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) WARN: 'including inaccessible elements by default'
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should fetch nested data when clicking on a dropdown FAILED
	AssertionError: expected 1 to equal 11
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should fetch nested data when calling API method `unstable_dataSource.fetchRows` FAILED
	AssertionError: expected 1 to equal 11
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should lazily fetch nested data when using `defaultGroupingExpansionDepth` FAILED
	AssertionError: expected +0 to be above +0
```

@lauri865
Copy link
Contributor

lauri865 commented Jan 29, 2025

When I add the dep back into useMemo:

LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
.
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should fetch nested data when clicking on a dropdown FAILED
	AssertionError: expected 3 to equal 2
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should fetch nested data when calling API method `unstable_dataSource.fetchRows` FAILED
	AssertionError: expected 2 to equal 1
LOG: 'RESET'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
LOG: 'useMemo'
Chrome Headless 133.0.0.0 (Mac OS 10.15.7) <DataGridPro /> - Data source tree data should lazily fetch nested data when using `defaultGroupingExpansionDepth` FAILED
	AssertionError: expected 2 to equal 1

@lauri865
Copy link
Contributor

lauri865 commented Jan 29, 2025

Modified useMockServer to return a stable reference for fetchRows with useEventCallback

Have many failing tests around datasource now (17 browser tests I think), all of them share the same flaw – fetchRows is not stable (changes when data changes for example) dataSource prop is unstable as a result, and everytime it changes, fetchRowSpy gets reset and datasource hooks trigger a new fetch.

I wonder if the datasource prop is something that should be aggressively memoized by default by the Datagrid (if the creators are struggling, think about the average developer 🙈) – feels like too easy to make mistakes, and something that ought not to actually need to change during rendering.

@arminmeh
Copy link
Contributor Author

arminmeh commented Jan 30, 2025

I wonder if the datasource prop is something that should be aggressively memoized by default by the Datagrid (if the creators are struggling, think about the average developer 🙈).

This only occurs because of unstable fetchRows from useMockServer. If you use fetch in prod then it should be perfectly fine. Depending on the implementation, using some other library hooks may be an issue. I mean, we can make it more stable but my feeling is that it is not a problem in a real world implementations.

all of them share the same flaw – fetchRows is not stable (changes when data changes for example)

Yes, this is the exact problem. I have basically worked around it.
It is all caused by this.

Data is created after the initial render. This makes fetchRows change, which changes the dataSource.
Thing is, I reset the counter after each dataSource change because the first version calls the spy, but the mock server returns an empty response, because data is not there yet.

Once the fetchRows stabilizes, it will start returning data and the counter will count the request properly.

You can add this after the response

const getRowsResponse = await fetchRows(url);
console.log('getRowsResponse', getRowsResponse);

and add verbose output in the serverOptions

const serverOptions = { minDelay: 0, maxDelay: 0, verbose: true };

that will log exactly one request (with tests expecting one request) even though useMemo appears multiple times.

I have noticed that some test are passing prematurely because they wait for one request which is an empty response and the second (real one) comes after that.

If you have time to fix this, so that we have stable fetchRows this that would be great.
I plan to look at it after I finish some other more pressing tasks

Modified useMockServer to return a stable reference for fetchRows with useEventCallback

This will cause the mock server to always return an empty response.

@lauri865
Copy link
Contributor

lauri865 commented Jan 30, 2025

Better yet would be to use a non-hook version of mockServer for testing purposes, as I suggested here #16395 (e.g. making sure the mockServer is ready before mounting any components, to avoid having to deal with unrelated state changes in tests)

@arminmeh arminmeh added the test label Jan 30, 2025
@arminmeh arminmeh merged commit f77d2af into mui:v7.x Jan 31, 2025
17 checks passed
@arminmeh arminmeh deleted the debouce-fetch-rows branch January 31, 2025 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cherry-pick The PR was cherry-picked from the newer alpha/beta/stable branch component: data grid This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature feature: Server integration Better integration with backends, e.g. data source plan: Pro Impact at least one Pro user test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants