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] Raf Timer stored in apiRef #506

Merged
merged 18 commits into from
Oct 30, 2020
Merged

Conversation

dtassone
Copy link
Member

@dtassone dtassone commented Oct 27, 2020

This PR allows to coordinates all calls to requestAnimationFrame

It fixes the raf violation
image

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

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

I'm not hands-on in the grid, so it's only feedback from a high-level perspective, the change seems to go in the opposite direction I was expecting. We are introducing a leaking side effect, an update scheduled in one use ref call can be canceled and never called again in another update, this will likely create bugs. I mean, it only works if the use raf hooks are used in the same component. Have you considered to share the update function instead of the then timer? This would guarantee the constraint and hence avoid dropped updates.

I don't understand why we need to use Raf in the first place. react-virtualized, react-window, react-virtuoso, react-virtual barely uses it. I would encourage we remove this hook from the codebase to make usage of Raf painful, the default solution being to defer rendering prioritization to React.

packages/grid/_modules_/grid/models/api/coreApi.ts Outdated Show resolved Hide resolved
packages/grid/_modules_/grid/models/api/coreApi.ts Outdated Show resolved Hide resolved
@oliviertassinari
Copy link
Member

oliviertassinari commented Oct 27, 2020

I'm having a closer look at the usage of raf:

  1. In useRow.js, we can remove it. There is a set state call that render. I haven't seen any end-to-end tests fail without. I mean, puppeteer tests are all red for me on master but karma one all passes. If this leads to a regression, it's a great time to add a nest test case.
  2. In useColumns.js, we should be able to remove it with the migration to the new state logic, updateColumns is a public API, it should set the state and tell React to rerender, it doesn't right now, which is likely a bug. Once fixed, we can drop useRafUpdate from the file.
  3. In useScrollFn.js, the use case looks correct, in which case, we don't need to share the request animation, it's a non-CPU intensive callback.

So it seems that we can/should remove the hook.

@dtassone
Copy link
Member Author

I'm having a closer look at the usage of raf:

  • In useRow.js, we can remove it. There is a set state call that render. I haven't seen any end-to-end tests fail without. I mean, puppeteer tests are all red for me on master but karma one all passes. If this leads to a regression, it's a great time to add a nest test case.
  • In useColumns.js, we should be able to remove it with the migration to the new state logic, updateColumns is a public API, it should set the state and tell React to rerender, it doesn't right now, which is likely a bug. Once fixed, we can drop useRafUpdate from the file.
  • In useScrollFn.js, the use case looks correct, in which case, we don't need to share the request animation, it's a non-CPU intensive callback.

So it seems that we can/should remove the hook.

Please try on the fast streaming stories.

@oliviertassinari
Copy link
Member

oliviertassinari commented Oct 28, 2020

Please try on the fast streaming stories.

Isn't streaming a different concern? Why apply the same solution for the other use cases? I definitely agree that for streaming we could considering rerendering at each RAF, bypassing React. But at the same time, isn't it the same with the onScroll events (it fires a lot and yet we don't use it)? In the above exploration, I believe streaming has no impact. 1. is already backed by a React state, 2. will need to be (it won't behave correctly without), 3. can be done with a set timeout or a RAF.

@dtassone
Copy link
Member Author

Please try on the fast streaming stories.

Isn't streaming a different concern? Why apply the same solution for the other use cases? I definitely agree that for streaming we could considering rerendering at each raf, bypassing React. But at the same time, isn't it the same with the onScroll events (it fires a lot)? In the above exploration, this has no impact. 1. is already backed by a React state, 2. will need to be (it won't behave correctly), 3. need to use a raf.

I'm not sure I understand what you mean.
If you update the rows super fast as in a streaming case then it needs to coordinate tightly with the scrolling events without blocking the UI.
I do not see it used directly in columns

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

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

We can't share rerendering between different components.

Conflicts:
	packages/grid/_modules_/grid/hooks/features/virtualization/useVirtualRows.ts
	packages/grid/_modules_/grid/hooks/utils/useScrollFn.ts
packages/grid/_modules_/grid/hooks/utils/useScrollFn.ts Outdated Show resolved Hide resolved
packages/grid/_modules_/grid/hooks/utils/useScrollFn.ts Outdated Show resolved Hide resolved
packages/grid/_modules_/grid/models/api/coreApi.ts Outdated Show resolved Hide resolved
expect(checkbox).to.have.property('checked', true);

fireEvent.click(screen.getByRole('cell', { name: 'Nike' }));
await raf();
expect(row!.classList.contains('Mui-selected')).to.equal(false);
expect(row!.classList.contains('Mui-selected')).to.equal(false, 'class mui-selected 2');
Copy link
Member

Choose a reason for hiding this comment

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

Like in Jest we don't use assertion descriptions. It's very often outdated and doesn't help much.

Suggested change
expect(row!.classList.contains('Mui-selected')).to.equal(false, 'class mui-selected 2');
expect(row!.classList.contains('Mui-selected')).to.equal(false);

Copy link
Member Author

Choose a reason for hiding this comment

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

this is to see where the fails in the ci

Copy link
Member

@oliviertassinari oliviertassinari Oct 29, 2020

Choose a reason for hiding this comment

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

Yes, I thought you were using Jest in the past, this isn't supported in Jest :p

Copy link
Member

Choose a reason for hiding this comment

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

Happy to keep it, my feedback, at its core, is that it's often ignored and get outdated after refactoring in the tests. So usually, we don't bother 🤷‍♂️

await raf();
expect(row!.classList.contains('Mui-selected')).to.equal(true);
await sleep(100)
expect(row!.classList.contains('Mui-selected')).to.equal(true, 'class mui-selected 1');
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
expect(row!.classList.contains('Mui-selected')).to.equal(true, 'class mui-selected 1');
expect(row!.classList.contains('Mui-selected')).to.equal(true);

Copy link
Member Author

Choose a reason for hiding this comment

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

By leaving this we know where the test can potentially failed. Up to you?

dtassone and others added 11 commits October 29, 2020 16:35
@dtassone dtassone merged commit 1f542a2 into mui:master Oct 30, 2020
@oliviertassinari
Copy link
Member

Browser tests are flaky after the change. Something is wrong with the logic.

dtassone added a commit to dtassone/material-ui-x that referenced this pull request Nov 9, 2020
* add rafTimer

Conflicts:
	packages/grid/_modules_/grid/hooks/features/virtualization/useVirtualRows.ts
	packages/grid/_modules_/grid/hooks/utils/useScrollFn.ts

* fix cyclic dep and cleanup

* fix import

* fix import

* trying to fix test in CI

* refactor scroll

* Update packages/grid/_modules_/grid/hooks/utils/useRafUpdate.ts

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>

* Update packages/grid/_modules_/grid/hooks/utils/useScrollFn.ts

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>

* fix tests

* prettier

* fix test

* fix test

* fix tests

* more sleep

* Update packages/grid/_modules_/grid/models/api/coreApi.ts

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>

* Update packages/grid/_modules_/grid/models/api/coreApi.ts

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>

* small refactoring

Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>
@zannager zannager added the component: data grid This is the name of the generic UI component, not the React module! label Jan 17, 2023
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
Development

Successfully merging this pull request may close these issues.

3 participants