So you are looking for loading data as you scroll, yes? Awesome—we've got you covered!
- Make sure you've read the documentation for
@virtualform/grid
. - This walkthrough won't care about visuals, etc. This is on you.
import { useGrid } from '@virtualform/grid'
const Grid = () => {
const { getRootProps, getWrapperProps, cells } = useGrid({
cells: {
amount: 1000,
width: 100,
height: 100,
},
})
const { style, ...rootProps } = getRootProps()
return (
<div style={{ ...style, height: '100vh' }} {...rootProps}>
<div {...getWrapperProps()}>
{cells.map((cell) => (
<div {...cell.getProps()}>Item {cell.index}</div>
))}
</div>
</div>
)
}
import { useGrid } from '@virtualform/grid'
import { useQuery } from 'query-lib' // this is fake; use the lib of your choice!
const Grid = () => {
const { data, isLoading } = useQuery('/api/pictures')
const { getRootProps, getWrapperProps, cells } = useGrid({
cells: {
amount: data?.pictures.length ?? 0,
width: 100,
height: 100,
},
})
const { style, ...rootProps } = getRootProps()
return (
<div style={{ ...style, height: '100vh' }} {...rootProps}>
{isLoading && <div>Loading initial data...</div>}
{!isLoading && (
<div {...getWrapperProps()}>
{cells.map((cell) => (
<div {...cell.getProps()}>
<img
style={{ width: '100%', height: '100%' }}
src={data.pictures[cell.index].url}
/>
</div>
))}
</div>
)}
</div>
)
}
The code above...
- Through
useQuery
(which can be any fetch function you like), we are fetching data from/api/pictures
. This hook returns us bothdata
andisLoading
. The latter, in this case, only indicates whether the initial data is loading or not (more on that later). - We replaced
cells.amount
from static1000
todata?.pictures.length ?? 0
, that tells Virtualform, hey dude, if data is loaded, lets use its length as the amount of cells, otherwise, we have no cells to display. - We separated our markup a little: we now display
Loading initial data...
while data is loading, otherwise we render the grid as expected.
import { useGrid } from '@virtualform/grid'
import { useQuery } from 'query-lib'
const Grid = () => {
const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } =
useQuery('/api/pictures')
const {
getRootProps,
getWrapperProps,
cells,
mountedRowsIndices,
rowsAmount,
} = useGrid({
cells: {
amount: data?.pictures.length ?? 0,
width: [50, 100],
height: 100,
},
})
const { style, ...rootProps } = getRootProps()
useEffect(() => {
const isFetchMoreRowMounted = mountedRowsIndices.includes(rowsAmount - 2)
const shouldFetchMore =
isFetchMoreRowMounted && hasNextPage && !isFetchingNextPage
if (!shouldFetchMore) {
return
}
fetchNextPage()
}, [isFetchingNextPage, hasNextPage, mountedRowsIndices])
return (
<div style={{ ...style, height: '100vh' }} {...rootProps}>
{isLoading && <div>Loading initial data...</div>}
{isFetchingNextPage && <div>Loading more results...</div>}
{!isLoading && (
<div {...getWrapperProps()}>
{cells.map((cell) => (
<div {...cell.getProps()}>
<img
style={{ width: '100%', height: '100%' }}
src={data.pictures[cell.index].url}
/>
</div>
))}
</div>
)}
</div>
)
}
Let's see what happened.
- We are now getting new variables from our
useQuery
:isFetchingNextPage
,hasNextPage
,fetchNextPage
. - We are now getting new variables from our
useGrid
:rowsAmount
,mountedRowsIndices
. - We called a
useEffect
hook with some dependencies:isFetchingNextPage
,hasNextPage
,mounteRows
. Whenever one of these variables change, the function passed to theuseEffect
will be called (pretty ordinary React code). - In the function passed to
useEffect
, we declared two variables:isFetchMoreRowMounted
: checks if the penultimate row is among the mounted rows by Virtualform. This is key for infinite loading—it's where we specify at which point of the scroll we must request for more data (or fetch the next page).shouldFetchMore
: checks if all the conditions are met in order to fetch more data. In our case, the penultimate row has to be mounted, the api cannot be fetching more results already and there should be more data to be fetched.
- We are now rendering a
Loading more results...
div to indicate more results are being fetched.
As you could see, Virtualform is only responsible for virtualization. It may sound tedious, but this is us helping you by assigning less responsibility to the lib than it should have. This actually benefits you, application developer, and us, library maintainers.
If you think about it, although we don't offer magical functions to automatically infinite load for you, you retain 100% of the power of how things should happen. In the future, your codebase will be thankful.
Anyways... Congratulations, you now have an infinite, virtualized grid!