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] Refactor state #412

Merged
merged 44 commits into from
Oct 26, 2020
Merged

[DataGrid] Refactor state #412

merged 44 commits into from
Oct 26, 2020

Conversation

dtassone
Copy link
Member

@dtassone dtassone commented Oct 7, 2020

No description provided.

@oliviertassinari oliviertassinari changed the title Just grid state [DataGrid] Refactor state Oct 25, 2020
@oliviertassinari oliviertassinari added component: data grid This is the name of the generic UI component, not the React module! core Infrastructure work going on behind the scenes labels Oct 25, 2020
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 are getting closer. I think that we should address the following before moving forward (so we keep master in a state that can be released at any time). Maybe @DanailH could help? :)

  1. 🚀 The documentation is unusable. There is a major performance regression on https://deploy-preview-412--material-ui-x.netlify.app/components/data-grid/. You can check this performance test, it becomes like the storybook (take about 8s to be ready).
  2. 📚 Could you add a description to the pull request? This would help to explain the issue, the solution, the options that were considered. If we do it orally, we will cover the problem on the surface. We won't also be able to go back to it in x months. Or even link to new developers joining the team. I think that the bigger the pull request is, the more relevant this feedback is.
  3. 🐛 The resizing feature is no longer working.

resizing

  1. 🚀 In the sorting feature, restoring the default sort order doesn't longer feel instant. It goes from 50ms to 500ms (on my machine)
  2. ⚛️ I think that changes in end-to-ends tests for refactorization are always something to be extremely cautious with. If the tests are well written and if the refacto implements the same behavior, they shouldn't be any changes. I have seen changes in the test that suggests regressions (skip, sleep, tests no longer act-synchronous).
  3. ⚛️ Some parts of the grid reducer logic seem not idiomatic to React, it might cause bugs. See the second review to have more info.
  4. 🚀 Click the select all rows freeze the whole UI for ~5s
  5. 🐛 The keyboard logic is broken. When you use it with two data tables on the same page, it jumps between the two. The focus leaks
  6. 🐛 Once you start using the keyboard logic, the virtualization becomes unresponsive. There are major white areas.
  7. 🐛 The keyboard logic is unresponsive, it takes 250ms easily to handle a press. It seems to be an infinite ref loop issue.

I have run all my tests with the main demo.
I'm having a look at what's going on with 1. 5. 6. and 7, see if I can help.


  1. and 7. handled in Performance issue dtassone/material-ui-x#3

internalOptions.autoHeight,
internalOptions.headerHeight,
internalOptions.rowHeight,
import useForkRef from '@material-ui/core/utils/useForkRef';
Copy link
Member

Choose a reason for hiding this comment

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

This import is invalid. It leads to bundling duplicate versions of the same modules (CJS + ESM, which harm bundle size).

Suggested change
import useForkRef from '@material-ui/core/utils/useForkRef';
import { useForkRef } from '@material-ui/core/utils';

We will get an error once we enable the eslint rule back:

https://github.com/mui-org/material-ui-x/blob/f7856e13759740fd21df73e1f5f3902fd1d08444/.eslintrc.js#L24-L25

We also have this issue in the main repo, mui/material-ui#23159 expose some cases.

@@ -1,7 +1,6 @@
import * as React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import styled, { createGlobalStyle } from 'styled-components';
import './app.less';
Copy link
Member

Choose a reason for hiding this comment

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

For any large pull requests. I think that we should strongly encourage to move any change that can be prune outside of it. For instance here, we go after fixing the build of the demo-app. We can deliver value by fixing it independently from the refactoring. Then, we can rebase this pull request on the fix once it lands in master.

const cellRef = React.useRef<HTMLDivElement>(null);

React.useEffect(() => {
if (hasFocus && cellRef.current) {
Copy link
Member

Choose a reason for hiding this comment

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

cellRef.current should always be defined, by contract with React.

Suggested change
if (hasFocus && cellRef.current) {
if (hasFocus) {

if it's not, something is wrong in the core structure, better not hiding it.

Copy link
Member Author

Choose a reason for hiding this comment

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

the initial value is null, and it gets defined after the component mount. So I can remove it and add a ! which won't change much.

Copy link
Member

Choose a reason for hiding this comment

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

! save bundle size but more importantly it allows us to not silently ignore the problem if, in a future refactorization, we forget to apply the ref correctly.


return <React.Fragment>{items}</React.Fragment>;
});
};
ColumnHeaderItemCollection.displayName = 'ColumnHeaderItemCollection';
Copy link
Member

Choose a reason for hiding this comment

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

It has no impact, the component isn't memo or forward ref, if we do, better name the function to get bundle size once it lands in production.

Suggested change
ColumnHeaderItemCollection.displayName = 'ColumnHeaderItemCollection';

Comment on lines 44 to +48
row,
rowIndex,
scrollSize,
cellFocus,
showCellRightBorder,
Copy link
Member

Choose a reason for hiding this comment

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

Best to keep the props sort ASC, more structure make it simpler to navigate it.

@@ -5,6 +5,7 @@
"declarationDir": "./dist",
"module": "es6",
"noImplicitAny": false,
"noUnusedLocals": false,
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
"noUnusedLocals": false,

Note that I normalize the tsconfig in #448.

Comment on lines +1 to +8
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


reselect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
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
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
reselect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==

@@ -17,7 +17,7 @@
"noImplicitThis": true,
"noImplicitAny": false,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedLocals": false,
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
"noUnusedLocals": false,
"noUnusedLocals": true,

tsconfig.json Show resolved Hide resolved
Comment on lines +143 to +144
// eslint-disable-next-line mocha/no-skipped-tests
xit('should throw if the rows has no id', function test() {
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
// eslint-disable-next-line mocha/no-skipped-tests
xit('should throw if the rows has no id', function test() {
it('should throw if the rows has no id', function test() {

@oliviertassinari
Copy link
Member

  1. and 7. handled in Performance issue dtassone/material-ui-x#3

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.

  1. 🐛 A new bug I have seen: If you add a onChange callback, it's called infinitely. For instance:
      <DataGrid
        page={page}
        onPageChange={(params) => {
          console.log('onchange')
          setPage(params.page);
        }}
        pageSize={5}
        pagination
        {...data}
      />

I had a closer look at 6. I have left a few extra comments where relevant :).

I don't understand how the new state structure solves "the problem". From what I understand, we are missing two important parts of the equation:

  • Updates across hook and components. How is useGridReducer different from React.useReducer? It seems to behave identically (at the exception that useGridReducer has a global imperative side effect).
    Here is an example of what I mean by "the problem". The useColumnReorder() needs to set in the state that the column field id Y is reordering. How will this notification ends re-rendering <ColumnHeaderItem> (and only) so it can add the correct CSS class name? I see that we have an useSelector equivalent API to redux: useGridReducer but it's not wired. Shouldn't we listen to the event emitter here? I assume the memo we have in place will prune the rendering.
  • The public API. How does it fit into [RFC] Change API state #190? For instance, controlled pagination. Forcing: <DataGrid page={1}> is not working, the page can be changed, from the internal state. It's not frozen on 1 as a developer would expect. The prop behaves like a default prop. A solution would probably start with something in this order:
diff --git a/packages/grid/_modules_/grid/hooks/features/pagination/usePagination.ts b/packages/grid/_modules_/grid/hooks/features/pagination/usePagination.ts
index 6af6f657..549697c4 100644
--- a/packages/grid/_modules_/grid/hooks/features/pagination/usePagination.ts
+++ b/packages/grid/_modules_/grid/hooks/features/pagination/usePagination.ts
@@ -99,9 +99,9 @@ export const usePagination = (apiRef: ApiRef): PaginationProps => {
     dispatch(setPaginationModeActionCreator({ paginationMode: options.paginationMode! }));
   }, [apiRef, dispatch, options.paginationMode]);

-  React.useEffect(() => {
-    setPage(options.page != null ? options.page : 1);
-  }, [options.page, setPage]);
+  if (options.page != null) {
+    setPage(options.page);
+  }

   React.useEffect(() => {
     if (!options.autoPageSize && options.pageSize) {

For the uncontrolled mode. Will we have a global defaultState prop? Will we allow to reduce all the events with a stateReducer prop?
For the controlled mode. Will we allow developer to force a state prop? Will we add a onStateChange prop?

apiRef: ApiRef | undefined,
selector: (state: any) => State,
) => {
const [state, ,] = useGridState(apiRef!);
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
const [state, ,] = useGridState(apiRef!);
const [state] = useGridState(apiRef!);

@dtassone dtassone merged commit 2abef4a into mui:master Oct 26, 2020
oliviertassinari added a commit to oliviertassinari/mui-x that referenced this pull request Oct 31, 2020
oliviertassinari added a commit to oliviertassinari/mui-x that referenced this pull request Nov 4, 2020
oliviertassinari added a commit that referenced this pull request Nov 4, 2020
dtassone added a commit to dtassone/material-ui-x that referenced this pull request Nov 9, 2020
Refactored state to attach it to apiRef. Performance issues will be treated in following PRs

* WIP state refactoring on pagination

* fix merging issues

* WIP working on the rowsReducer and global state

* fixes state refactoring finalizing api

* refactored grid reducer

* fix issue with state and cleanup

* fix state and added sortedSelctor for viewport

* prettier

* fix state virtualisation

* small refactoring with selector

* rollback lint rules

* remove options prop to useGridSelector

* prettier

* cleanup commented code

* fix pagination and rendering issues

* fix sorting and refactored hooks props

* Refactored useSorting to new gridState

* rebased and fix issues

* cleanup

* prettier

* fix test

* rebased

* fix demo app

* small refactoring on header item

* fix dependency cycle

* fix index

* prettier

* removed unused fn

* fixing test

* small refactoringg

* prettier

* perf improvements and keyboard refactoring

* improve perf and fix keyboard and test

* move virtualisation folder

* prettier

* refactor useComponents and useEvents

* yarn docs ts formatted

* fix demos and issue with resizing

* fix types in doc

* small fix prettier

* fix rows perf, and prettier

* fix dependency array

* fix prettier

* restored rowIndex
dtassone pushed a commit to dtassone/material-ui-x that referenced this pull request Nov 9, 2020
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! core Infrastructure work going on behind the scenes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants