Use useInfiniteQuery instead of useQuery, if you want to show large
data gradually more. For instance, you have many numbered pages, and you
want to show the first ten pages initially. After clicking on
Show more pages, the user should see three pages more than before. For
this case, you can useInfiniteQuery as shown in the following example.
import { useInfiniteQuery } from "blitz"
import getProjects from "app/projects/queries/getProjects"
function Projects(props) {
const [
projectPages,
{ isFetching, isFetchingNextPage, fetchNextPage, hasNextPage },
] = useInfiniteQuery(
getProjects,
(page = { take: 3, skip: 0 }) => page,
{
getNextPageParam: (lastPage) => lastPage.nextPage,
}
)
return (
<>
{projectPages.map((page, i) => (
<React.Fragment key={i}>
{page.projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || !!isFetchingNextPage}
>
{isFetchingNextPage
? "Loading more..."
: hasNextPage
? "Load More"
: "Nothing more to load"}
</button>
</div>
<div>
{isFetching && !isFetchingNextPage ? "Fetching..." : null}
</div>
</>
)
}And here's the query to work with that:
import { paginate, resolver } from "blitz"
import db, { Prisma } from "db"
interface GetProjectsInput
extends Pick<
Prisma.ProjectFindManyArgs,
"where" | "orderBy" | "skip" | "take"
> {}
export default resolver.pipe(
resolver.authorize(),
async ({ where, orderBy, skip = 0, take = 100 }: GetProjectsInput) => {
const { items: projects, hasMore, nextPage, count } = await paginate({
skip,
take,
count: () => db.project.count({ where }),
query: (paginateArgs) =>
db.project.findMany({ ...paginateArgs, where, orderBy }),
})
return {
projects,
nextPage,
hasMore,
count,
}
}
)const [
pagesOfQueryResults,
{
pageParams,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
...extras
}
] = useInfiniteQuery(queryResolver, getQueryInputArguments, {
...options,
getNextPageParam: (lastPage, allPages) => lastPage.nextPage,
getPreviousPageParam: (firstPage, allPages) => firstPage.nextPage,
})queryResolver: A Blitz query resolvergetQueryInputArguments: (fetchNextPageVariable) => queryInputArgumentsqueryInputArgumentsfetchNextPageVariable is undefined.fetchNextPageVariable is whatever is returned
from getNextPageParam()optionsThe options are identical to the options for the useQuery hook with the addition of the following:
getNextPageParam: (lastPage, allPages) => unknown | undefinedgetQueryInputArguments().undefined to indicate there is no next page available.getPreviousPageParam: (firstPage, allPages) => unknown | undefinedgetQueryInputArguments().undefined to indicate there is no previous page available.[pagesOfQueryResults, queryExtras]
pagesOfQueryResults: TData[]queryExtras: ObjectThe query extras for useInfiniteQuery are identical to the query extas
for the useQuery hook with the addition of the
following:
pageParams: unknown[]isFetchingNextPage: booleantrue while fetching the next page with fetchNextPage.isFetchingPreviousPage: booleantrue while fetching the previous page with
fetchPreviousPage.fetchNextPage: (options?: FetchNextPageOptions) => Promise<UseInfiniteQueryResult>options.pageParam: unknown allows you to manually specify a page
param instead of using getNextPageParam.fetchPreviousPage: (options?: FetchPreviousPageOptions) => Promise<UseInfiniteQueryResult>options.pageParam: unknown allows you to manually specify a page
param instead of using getPreviousPageParam.hasNextPage: booleantrue if there is a next page to be fetched (known via
the getNextPageParam option).hasPreviousPage: booleantrue if there is a previous page to be fetched (known
via the getPreviousPageParam option).setQueryData() - Function(newData, opts) => voidnewData can be an object of new data or a function that receives the
old data and returns the new datarefetch() to
ensure the data is correct. Disable refetch by passing an options
object {refetch: false} as the second argument.setQueryData()