diff --git a/examples/grid-infinite-data.tsx b/examples/grid-infinite-data.tsx new file mode 100644 index 000000000..b93120dd5 --- /dev/null +++ b/examples/grid-infinite-data.tsx @@ -0,0 +1,32 @@ +import * as React from 'react' +import { useState } from 'react' +import { VirtuosoGrid } from '../src' + +function generateItems(length: number) { + return Array.from({ length }, (_, index) => `My Item ${index}`) +} + +const itemContent = (_: number, data: string) => { + return
{data}
+} +export function Example() { + const [data, setData] = useState(() => generateItems(5)) + + const loadMore = () => { + setTimeout(() => { + setData((prevData) => { + return generateItems(prevData.length + 5) + }) + }, 100) + } + + return ( +
+ +
+ ) +} diff --git a/src/gridSystem.ts b/src/gridSystem.ts index c3e47a6e5..917d83901 100644 --- a/src/gridSystem.ts +++ b/src/gridSystem.ts @@ -310,11 +310,25 @@ export const gridSystem = /*#__PURE__*/ u.system( const endReached = u.streamFromEmitter( u.pipe( - u.duc(gridState), - u.filter(({ items }) => items.length > 0), - u.withLatestFrom(totalCount, hasScrolled), - u.filter(([{ items }, totalCount, hasScrolled]) => hasScrolled && items[items.length - 1].index === totalCount - 1), - u.map(([, totalCount]) => totalCount - 1), + u.combineLatest(gridState, totalCount), + u.filter(([{ items }]) => items.length > 0), + u.withLatestFrom(hasScrolled), + u.filter(([[gridState, totalCount], hasScrolled]) => { + const lastIndex = gridState.items[gridState.items.length - 1].index + const isLastItemRendered = lastIndex === totalCount - 1 + + // User has scrolled + if (hasScrolled) return isLastItemRendered + + // User has not scrolled, so check whether grid is fully rendered + const isFullyRendered = + gridState.bottom > 0 && gridState.itemHeight > 0 && gridState.offsetBottom === 0 && gridState.items.length === totalCount + + return isFullyRendered && isLastItemRendered + }), + u.map(([[, totalCount]]) => { + return totalCount - 1 + }), u.distinctUntilChanged() ) )