-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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] Add 'gridReady' event to notify the user when the grid has been mounted #6568
base: v6.x
Are you sure you want to change the base?
Conversation
Netlify deploy previewNetlify deploy preview: https://deploy-preview-6568--material-ui-x.netlify.app/ Updated pagesNo updates. These are the results for the performance tests:
|
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 destination branch should be next
. As far as I can see this is not a critical issue. We can actually even consider it as an enhancement.
@DanailH done, and I have accidentally removed other reviewers. |
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.
Thanks for the contribution! Could you fix the pipeline and provide a CodeSandbox showing that this PR solves the use case in #6411. I'm not very sure it will fix because the scrollTOp
is reset in an effect when the grid is mounted:
mui-x/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
Lines 208 to 216 in 7a7977f
React.useEffect(() => { | |
if (disableVirtualization) { | |
renderZoneRef.current!.style.transform = `translate3d(0px, 0px, 0px)`; | |
} else { | |
// TODO a scroll reset should not be necessary | |
rootRef.current!.scrollLeft = 0; | |
rootRef.current!.scrollTop = 0; | |
} | |
}, [disableVirtualization]); |
I was expecting something like
diff --git a/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
index 2b773e035..f16e2999a 100644
--- a/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
+++ b/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
@@ -205,7 +205,7 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
containerWidth,
]);
- React.useEffect(() => {
+ React.useLayoutEffect(() => {
if (disableVirtualization) {
renderZoneRef.current!.style.transform = `translate3d(0px, 0px, 0px)`;
} else {
@@ -213,6 +213,10 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
rootRef.current!.scrollLeft = 0;
rootRef.current!.scrollTop = 0;
}
+
+ if (onReady) {
+ onReady();
+ }
}, [disableVirtualization]);
React.useEffect(() => {
@m4theushw in diff --git a/packages/grid/x-data-grid/src/hooks/core/useGridStateInitialization.ts b/packages/grid/x-data-grid/src/hooks/core/useGridStateInitialization.ts
index 1662575f..debcf7a3 100644
--- a/packages/grid/x-data-grid/src/hooks/core/useGridStateInitialization.ts
+++ b/packages/grid/x-data-grid/src/hooks/core/useGridStateInitialization.ts
@@ -36,7 +36,7 @@ export const useGridStateInitialization = <Api extends GridApiCommon>(
newState = state;
}
- if (apiRef.current.state === newState) {
+ if (isDeepEqual(apiRef.current.state, newState)) {
return false;
} Demo: https://codesandbox.io/s/admiring-scott-chcls3?file=/demo.tsx |
Hey @m4theushw it('should update headers when `columnGroupingModel` is modified', () => {
...
setProps({ columnGroupingModel: [{ groupId: 'col2', children: [{ field: 'col2' }] }] });
expect(screen.queryAllByRole('row')).to.have.length(3);
} the problem was when the states change Demo: https://codesandbox.io/s/silly-hypatia-xgs712?file=/demo.tsx you have to click the update button twice to update it. fix --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts
+++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts
@@ -174,6 +174,7 @@ export const useGridColumnGrouping = (
},
};
});
+ apiRef.current.forceUpdate();
}, [
apiRef,
columnFields, this seemed to fix it should I create another PR for this |
apiRef.current.windowRef = { current: node }; | ||
const unsubscribe = apiRef.current.subscribeEvent('stateChange', () => { | ||
setTimeout(() => { | ||
apiRef.current.publishEvent('gridReady'); |
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 doesn't seem like it fixes the issue: https://codesandbox.io/s/confident-forest-6tizwv?file=/src/App.tsx
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.
does it not scroll to the index for you?
I add setTimeout
because some states like rowMeta
might not finish initializing after row data is set. I am experimenting with a way to check if all the states have finished before gridReady
is triggered.
const unsubscribe = apiRef.current.subscribeEvent('stateChange', (newState) => {
if (newState.rowsMeta.currentPageTotalHeight > 0) {
setTimeout(() => {
apiRef.current.publishEvent('gridReady');
}, 0);
unsubscribe();
}
});
}
const unsubscribe = apiRef.current.subscribeEvent('stateChange', () => { | ||
setTimeout(() => { | ||
apiRef.current.publishEvent('gridReady'); | ||
}, 5); |
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.
Regarding the original issue #6411 specifically, would gridReady
solve it if the grid is rendered in a loading state while waiting for rows data to load?
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.
yes, that's why I add for 'stateChange' listener. if the rows data did not load it won't be fired. the downside is if you create an empty DataGrid, 'gridReady' won't be triggered.
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.
here is an example. https://codesandbox.io/s/laughing-noyce-rm95xy?file=/index.tsx
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.
If the grid is empty or in the loading state it's still "ready".
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
(node: HTMLDivElement) => { | ||
if (node && apiRef.current.windowRef?.current == null) { | ||
apiRef.current.windowRef = { current: node }; | ||
const triggerGridReadyEvent = debounce(() => apiRef.current.publishEvent('gridReady'), 100); |
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 debounce added is fighting against
mui-x/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
Lines 212 to 214 in 4d77507
// TODO a scroll reset should not be necessary | |
rootRef.current!.scrollLeft = 0; | |
rootRef.current!.scrollTop = 0; |
Why not try #6568 (review) that doesn't require setTimeout
? We should try to avoid setTimeout
.
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.
Why not try #6568 (review) that doesn't require setTimeout? We should try to avoid setTimeout
I have tried it, but 'gridReady' is getting triggered multiple times. I could not get it to be triggered only 1 time.
diff --git a/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx b/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
index 782d3db54..b5e7ccf87 100644
--- a/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
+++ b/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { unstable_useForkRef as useForkRef } from '@mui/utils';
+import { debounce } from '@mui/material/utils';
import { useGridApiContext } from '../../utils/useGridApiContext';
import { useGridRootProps } from '../../utils/useGridRootProps';
import { useGridSelector } from '../../utils/useGridSelector';
@@ -97,6 +98,10 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
getRowProps,
} = props;
+ const triggerGridReadyEvent = React.useMemo(
+ () => debounce(() => apiRef.current.publishEvent('gridReady'), 300),
+ [apiRef],
+ );
const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector);
const columnsTotalWidth = useGridSelector(apiRef, gridColumnsTotalWidthSelector);
const cellFocus = useGridSelector(apiRef, gridFocusCellSelector);
@@ -205,7 +210,7 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
containerWidth,
]);
- React.useEffect(() => {
+ React.useLayoutEffect(() => {
if (disableVirtualization) {
renderZoneRef.current!.style.transform = `translate3d(0px, 0px, 0px)`;
} else {
@@ -213,7 +218,13 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
rootRef.current!.scrollLeft = 0;
rootRef.current!.scrollTop = 0;
}
- }, [disableVirtualization]);
+
+ apiRef.current.subscribeEvent('stateChange', (newState) => {
+ if (newState.rowsMeta.currentPageTotalHeight > 0) {
+ triggerGridReadyEvent();
+ }
+ });
+ }, [disableVirtualization, triggerGridReadyEvent, apiRef]);
this is how I tried to implement it.
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.
hey @m4theushw
i was looking at
mui-x/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx
Lines 212 to 214 in 4d77507
// TODO a scroll reset should not be necessary | |
rootRef.current!.scrollLeft = 0; | |
rootRef.current!.scrollTop = 0; |
and I think they are getting called too early before the rows are populated, I do not think they have any effect. I have tried rootRef.current!.scrollTop = 100
. and it does not do anything. also when I logged rowMeta
its currentPageTotalHeight
is 0. so scrolling at that point has no effect.
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.
Without this code, if you scroll to the middle of the viewport, disable virtualization with disableVirtualization=true
, then re-enable it again, the scroll position will change a bit. Resetting the scroll was better than having this small scroll.
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.
hey @m4theushw, I have managed useEffect
to be called only once. and I have put the code in useGridVirtualScroller
.
@yaredtsy can we add tests to see the track of the number of times the
These are off the top of my head. The first 4 IMO are 100% needed so we know what we want to achieve. |
hey @DanailH |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
packages/grid/x-data-grid-pro/src/tests/events.DataGridPro.test.tsx
Outdated
Show resolved
Hide resolved
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
Signed-off-by: yared tsegaye <[email protected]>
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
@yaredtsy Hi, I have the same issue that is described in the pull request. Could you please at least add gridReady event? |
@cherniavskii we should probably either close this PR or continue working on it to avoid giving false hope 👍 |
Fixes #6411
Problem
we can not use
apiRef.current
inuseEffect
. becauseapiRef.current.windowRef
is null in the begging and we can not tell when it is ready to use. so the only solution was to use it insetTimout
.Solution
i have created an event called
gridReady
which will get triggered when the state initialization is finished. user can subscribe to it to get notified when the grid is ready to interact.