-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 onRowsScrollEnd to support infinite loading #1199
Merged
DanailH
merged 38 commits into
mui:master
from
DanailH:feature/DataGrid-404-infinite-loading
Mar 18, 2021
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
c3c97d9
WIP
DanailH 848ba04
Finish the features logic
DanailH ef052c4
Fix formmating
DanailH afd4715
Merge branch 'master' of github.com:mui-org/material-ui-x into featur…
DanailH 0fa88ca
Add storybook demo
DanailH d1d177c
Review comments
DanailH 8e1349b
Update useDemoData hook
DanailH 82927cb
refactor
DanailH 68ea707
Move size selectors to separate file
DanailH e7f0482
Rework events
DanailH b25717e
move container size selectors
DanailH 2052d3c
Add params to the callback
DanailH 1d02608
Revert useDemoData changes
DanailH 2fe73eb
Add test and docs and prep the PR for review
DanailH 0395181
rename events
DanailH a3635c0
Resolve conflicts
DanailH d5d94b4
Update docs/src/pages/components/data-grid/rendering/rendering.md
DanailH 2a0dd74
PR review comments
DanailH 8004dea
resolve conflicts
DanailH 02c22c2
Move Infinite loading docs under rows
DanailH 1c5991d
Use XGrid in demos
DanailH ae1dc1c
Update example code
DanailH 22e0167
add new scroll param prop
DanailH 657fbd8
make the feature pro
DanailH 246eece
Flatten if statement
DanailH 24de8a6
Update packages/grid/data-grid/src/DataGrid.tsx
DanailH 3bd15dd
Update packages/grid/_modules_/grid/constants/eventsConstants.ts
DanailH 3eac46f
Fix pr comments
DanailH 0a1b799
Merge branch 'feature/DataGrid-404-infinite-loading' of github.com:Da…
DanailH 182456d
Polish demos
DanailH f228c90
Sort out grid props
DanailH 18c24d6
Use Danail tip
oliviertassinari 8952a1b
remove console.log
oliviertassinari 1d655e8
remove absoluteTop and depend on realScroll
DanailH 9af4f66
add additional test
DanailH cf50ca5
add selector
DanailH 84de4e3
Load the correct package
DanailH 6ba992e
Add new api
DanailH File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
docs/src/pages/components/data-grid/rows/InfiniteLoadingGrid.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import * as React from 'react'; | ||
import { XGrid, GridOverlay } from '@material-ui/x-grid'; | ||
import { | ||
useDemoData, | ||
getRealData, | ||
getCommodityColumns, | ||
} from '@material-ui/x-grid-data-generator'; | ||
import LinearProgress from '@material-ui/core/LinearProgress'; | ||
|
||
const MAX_ROW_LENGTH = 500; | ||
|
||
async function sleep(duration) { | ||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(); | ||
}, duration); | ||
}); | ||
} | ||
|
||
function CustomLoadingOverlay() { | ||
return ( | ||
<GridOverlay> | ||
<div style={{ position: 'absolute', top: 0, width: '100%' }}> | ||
<LinearProgress /> | ||
</div> | ||
</GridOverlay> | ||
); | ||
} | ||
|
||
export default function InfiniteLoadingGrid() { | ||
const [loading, setLoading] = React.useState(false); | ||
const [loadedRows, setLoadedRows] = React.useState([]); | ||
const mounted = React.useRef(true); | ||
const { data } = useDemoData({ | ||
dataSet: 'Commodity', | ||
rowLength: 20, | ||
maxColumns: 6, | ||
}); | ||
|
||
const loadServerRows = async (newRowLength) => { | ||
setLoading(true); | ||
const newData = await getRealData(newRowLength, getCommodityColumns()); | ||
// Simulate network throttle | ||
await sleep(Math.random() * 500 + 100); | ||
|
||
if (mounted.current) { | ||
setLoading(false); | ||
setLoadedRows(loadedRows.concat(newData.rows)); | ||
} | ||
}; | ||
|
||
const handleOnRowsScrollEnd = (params) => { | ||
if (loadedRows.length <= MAX_ROW_LENGTH) { | ||
loadServerRows(params.viewportPageSize); | ||
} | ||
}; | ||
|
||
React.useEffect(() => { | ||
return () => { | ||
mounted.current = false; | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<div style={{ height: 400, width: '100%' }}> | ||
<XGrid | ||
{...data} | ||
rows={data.rows.concat(loadedRows)} | ||
loading={loading} | ||
hideFooterPagination | ||
onRowsScrollEnd={handleOnRowsScrollEnd} | ||
components={{ | ||
LoadingOverlay: CustomLoadingOverlay, | ||
}} | ||
/> | ||
</div> | ||
); | ||
} |
78 changes: 78 additions & 0 deletions
78
docs/src/pages/components/data-grid/rows/InfiniteLoadingGrid.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import * as React from 'react'; | ||
import { XGrid, GridOverlay } from '@material-ui/x-grid'; | ||
import { | ||
useDemoData, | ||
getRealData, | ||
getCommodityColumns, | ||
} from '@material-ui/x-grid-data-generator'; | ||
import LinearProgress from '@material-ui/core/LinearProgress'; | ||
|
||
const MAX_ROW_LENGTH = 500; | ||
|
||
async function sleep(duration: number) { | ||
return new Promise<void>((resolve) => { | ||
setTimeout(() => { | ||
resolve(); | ||
}, duration); | ||
}); | ||
} | ||
|
||
function CustomLoadingOverlay() { | ||
return ( | ||
<GridOverlay> | ||
<div style={{ position: 'absolute', top: 0, width: '100%' }}> | ||
<LinearProgress /> | ||
</div> | ||
</GridOverlay> | ||
); | ||
} | ||
|
||
export default function InfiniteLoadingGrid() { | ||
const [loading, setLoading] = React.useState(false); | ||
const [loadedRows, setLoadedRows] = React.useState<any>([]); | ||
const mounted = React.useRef(true); | ||
const { data } = useDemoData({ | ||
dataSet: 'Commodity', | ||
rowLength: 20, | ||
maxColumns: 6, | ||
}); | ||
|
||
const loadServerRows = async (newRowLength) => { | ||
setLoading(true); | ||
const newData = await getRealData(newRowLength, getCommodityColumns()); | ||
// Simulate network throttle | ||
await sleep(Math.random() * 500 + 100); | ||
|
||
if (mounted.current) { | ||
setLoading(false); | ||
setLoadedRows(loadedRows.concat(newData.rows)); | ||
} | ||
}; | ||
|
||
const handleOnRowsScrollEnd = (params) => { | ||
if (loadedRows.length <= MAX_ROW_LENGTH) { | ||
loadServerRows(params.viewportPageSize); | ||
} | ||
}; | ||
|
||
React.useEffect(() => { | ||
return () => { | ||
mounted.current = false; | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<div style={{ height: 400, width: '100%' }}> | ||
<XGrid | ||
{...data} | ||
rows={data.rows.concat(loadedRows)} | ||
loading={loading} | ||
hideFooterPagination | ||
onRowsScrollEnd={handleOnRowsScrollEnd} | ||
components={{ | ||
LoadingOverlay: CustomLoadingOverlay, | ||
}} | ||
/> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages/grid/_modules_/grid/hooks/features/infiniteLoader/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useGridInfiniteLoader'; |
47 changes: 47 additions & 0 deletions
47
packages/grid/_modules_/grid/hooks/features/infiniteLoader/useGridInfiniteLoader.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import * as React from 'react'; | ||
import { optionsSelector } from '../../utils/optionsSelector'; | ||
import { GridApiRef } from '../../../models/api/gridApiRef'; | ||
import { useGridSelector } from '../core/useGridSelector'; | ||
import { GRID_ROWS_SCROLL, GRID_ROWS_SCROLL_END } from '../../../constants/eventsConstants'; | ||
import { gridContainerSizesSelector } from '../../root/gridContainerSizesSelector'; | ||
import { useGridApiEventHandler } from '../../root/useGridApiEventHandler'; | ||
import { GridRowScrollEndParams } from '../../../models/params/gridRowScrollEndParams'; | ||
import { visibleGridColumnsSelector } from '../columns/gridColumnsSelector'; | ||
|
||
export const useGridInfiniteLoader = (apiRef: GridApiRef): void => { | ||
const options = useGridSelector(apiRef, optionsSelector); | ||
const containerSizes = useGridSelector(apiRef, gridContainerSizesSelector); | ||
oliviertassinari marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const visibleColumns = useGridSelector(apiRef, visibleGridColumnsSelector); | ||
const isInScrollBottomArea = React.useRef<boolean>(false); | ||
|
||
const handleGridScroll = React.useCallback(() => { | ||
if (!containerSizes) { | ||
return; | ||
} | ||
|
||
const scrollPosition = apiRef.current.getScrollPosition(); | ||
const scrollPositionBottom = | ||
scrollPosition.top + containerSizes.windowSizes.height + options.scrollEndThreshold; | ||
|
||
if (scrollPositionBottom < containerSizes.dataContainerSizes.height) { | ||
isInScrollBottomArea.current = false; | ||
} | ||
|
||
if ( | ||
scrollPositionBottom >= containerSizes.dataContainerSizes.height && | ||
!isInScrollBottomArea.current | ||
) { | ||
const rowScrollEndParam: GridRowScrollEndParams = { | ||
api: apiRef, | ||
visibleColumns, | ||
viewportPageSize: containerSizes.viewportPageSize, | ||
virtualRowsCount: containerSizes.virtualRowsCount, | ||
}; | ||
apiRef.current.publishEvent(GRID_ROWS_SCROLL_END, rowScrollEndParam); | ||
isInScrollBottomArea.current = true; | ||
} | ||
}, [options, containerSizes, apiRef, visibleColumns]); | ||
|
||
useGridApiEventHandler(apiRef, GRID_ROWS_SCROLL, handleGridScroll); | ||
useGridApiEventHandler(apiRef, GRID_ROWS_SCROLL_END, options.onRowsScrollEnd); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/grid/_modules_/grid/hooks/features/pagination/useGridPagination.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
packages/grid/_modules_/grid/hooks/features/virtualization/renderingStateSelector.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,11 @@ | ||
import { createSelector } from 'reselect'; | ||
import { GridScrollParams } from '../../../models/params/gridScrollParams'; | ||
import { GridState } from '../core/gridState'; | ||
import { InternalRenderingState } from './renderingState'; | ||
|
||
export const renderStateSelector = (state: GridState) => state.rendering; | ||
export const scrollStateSelector = createSelector< | ||
GridState, | ||
InternalRenderingState, | ||
GridScrollParams | ||
>(renderStateSelector, (renderingState) => renderingState.realScroll); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
there is also a rowLength prop that you can set so the footer shows the correct amount of rows and the scrollbar should size accordingly
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.
I don't see a
rowLength
prop on the grid. The footer is showing the total rows currently.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.
Sorry
rowCount?: number;
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 don't you pass the realScroll state in the event params.
The event is fired from
updateViewport
where all the required params are, so you could just change the event payload and pass the real scroll params as well as the rendering scroll params.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.
Ok to summarise our call from yesterday - I will follow up on part for the rowCount and the functionality where all the rows are allocated in advance and a callback is called requestion for a specific range of rows to be loaded. I still think that the feature as it now brings value and the extra mile of making it work in combination with rowCount can be done afterward.
PS: I removed my other comment -> result -> fixed.
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.
Much better without the absoluteTop 👍 .
Ok, let's clean up this one a bit more and but scope this PR to the current feature.
Please open an issue describing the rest of the feature with the rowCount. Those needs to work together.
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 the ticket -> #1247