Use usePaginatedQuery
instead of useQuery
, if you want to divide large
data into smaller contiguous intervals of data. For instance, you have
many numbered pages, and you want to show the first three pages initially.
After clicking on Show next pages
, the user should see the following
three pages only. For this case, you can usePaginatedQuery
as shown in
the following example.
import { Suspense } from "react"
import {
Link,
BlitzPage,
usePaginatedQuery,
useRouterQuery,
useRouter,
Routes,
} from "blitz"
import getProjects from "app/products/queries/getProjects"
const ITEMS_PER_PAGE = 3
const Projects = () => {
const router = useRouter()
const page = Number(router.query.page) || 0
const [{ projects, hasMore }] = usePaginatedQuery(getProjects, {
orderBy: { id: "asc" },
skip: ITEMS_PER_PAGE * page,
take: ITEMS_PER_PAGE,
})
const goToPreviousPage = () =>
router.push({ query: { page: page - 1 } })
const goToNextPage = () => router.push({ query: { page: page + 1 } })
return (
<div>
{projects.map((project) => (
<p key={project.id}>
<Link href={Routes.Project({ handle: project.handle })}>
<a>{project.name}</a>
</Link>
</p>
))}
<button disabled={page === 0} onClick={goToPreviousPage}>
Previous
</button>
<button disabled={!hasMore} onClick={goToNextPage}>
Next
</button>
</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 [
queryResult,
{
dataUpdatedAt,
error,
errorUpdatedAt,
failureCount,
isError,
isFetched,
isFetchedAfterMount,
isFetching,
isIdle,
isLoading,
isLoadingError,
isPlaceholderData,
isPreviousData,
isRefetchError,
isStale,
isSuccess,
refetch,
remove,
status,
setQueryData,
},
] = usePaginatedQuery(queryResolver, queryInputArguments, options)
queryResolver:
A Blitz query resolverqueryInputArguments
queryResolver
options
The options are identical to the options for the useQuery hook
[queryResult, queryExtras]
queryResult: TData
undefined
.queryExtras: Object
status: String
idle
if the query is idle. This only happens if a query is
initialized with enabled: false
and no initial data is available.loading
if the query is in a "hard" loading state. This means
there is no cached data and the query is currently fetching, eg
isFetching === true
error
if the query attempt resulted in an error. The corresponding
error
property has the error received from the attempted fetchsuccess
if the query has received a response with no errors and is
ready to display its data. The corresponding data
property on the
query is the data received from the successful fetch or if the
query's enabled
property is set to false
and has not been
fetched yet data
is the first initialData
supplied to the query
on initialization.isIdle: boolean
status
variable above, provided for
convenience.isLoading: boolean
status
variable above, provided for
convenience.isSuccess: boolean
status
variable above, provided for
convenience.isError: boolean
status
variable above, provided for
convenience.isLoadingError: boolean
true
if the query failed while fetching for the first time.isRefetchError: boolean
true
if the query failed while refetching.data: TData
undefined
.dataUpdatedAt: number
status
as "success"
.error: null | TError
null
errorUpdatedAt: number
status
as "error"
.isStale: boolean
true
if the data in the cache is invalidated or if the data
is older than the given staleTime
.isPlaceholderData: boolean
true
if the data shown is the placeholder data.isPreviousData: boolean
true
when data from the previous query is returned.isFetched: boolean
true
if the query has been fetched.isFetchedAfterMount: boolean
true
if the query has been fetched after the component
mounted.isFetching: boolean
true
so long as enabled
is set to false
true
if the query is currently fetching, including
background fetching.failureCount: number
0
when the query succeeds.refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>
throwOnError: true
optioncancelRefetch
is true
, then the current request will be
cancelled before a new request is maderemove: () => void
setQueryData()
- Function(newData, opts) => Promise<void>
newData
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()
.