🚀Announcing Flightcontrol - Easily Deploy Blitz.js and Next.js to AWS 🚀
Back to Documentation Menu

usePaginatedQuery

Topics

Jump to a Topic

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.

Example

import { usePaginatedQuery } from "@blitzjs/rpc"
import { Routes } from "@blitzjs/next"
import { useRouter } from "next/router"
import Link from "next/link"
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 } from "blitz"
import { resolver } from "@blitzjs/rpc"
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,
    }
  }
)

API

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)

Arguments

  • queryResolver: A Blitz query resolver
    • Required
  • queryInputArguments
    • Required
    • The arguments that will be passed to queryResolver
  • options
    • Optional

Options

The options are identical to the options for the useQuery hook

Returns

[queryResult, queryExtras]

queryResult: TData
  • Defaults to undefined.
  • The last successfully resolved data for the query.
queryExtras: Object
  • status: String
    • Will be:
      • 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 fetch
      • success 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
    • A derived boolean from the status variable above, provided for convenience.
  • isLoading: boolean
    • A derived boolean from the status variable above, provided for convenience.
  • isSuccess: boolean
    • A derived boolean from the status variable above, provided for convenience.
  • isError: boolean
    • A derived boolean from the status variable above, provided for convenience.
  • isLoadingError: boolean
    • Will be true if the query failed while fetching for the first time.
  • isRefetchError: boolean
    • Will be true if the query failed while refetching.
  • data: TData
    • Defaults to undefined.
    • The last successfully resolved data for the query.
  • dataUpdatedAt: number
    • The timestamp for when the query most recently returned the status as "success".
  • error: null | TError
    • Defaults to null
    • The error object for the query, if an error was thrown.
  • errorUpdatedAt: number
    • The timestamp for when the query most recently returned the status as "error".
  • isStale: boolean
    • Will be true if the data in the cache is invalidated or if the data is older than the given staleTime.
  • isPlaceholderData: boolean
    • Will be true if the data shown is the placeholder data.
  • isPreviousData: boolean
    • Will be true when data from the previous query is returned.
  • isFetched: boolean
    • Will be true if the query has been fetched.
  • isFetchedAfterMount: boolean
    • Will be true if the query has been fetched after the component mounted.
    • This property can be used to not show any previously cached data.
  • isFetching: boolean
    • Defaults to true so long as enabled is set to false
    • Will be true if the query is currently fetching, including background fetching.
  • failureCount: number
    • The failure count for the query.
    • Incremented every time the query fails.
    • Reset to 0 when the query succeeds.
  • refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>
    • A function to manually refetch the query.
    • If the query errors, the error will only be logged. If you want an error to be thrown, pass the throwOnError: true option
    • If cancelRefetch is true, then the current request will be cancelled before a new request is made
  • remove: () => void
    • A function to remove the query from the cache.
  • setQueryData() - Function(newData, opts) => Promise<void>
    • A function to manually update the cache for a query.
    • newData can be an object of new data or a function that receives the old data and returns the new data
    • This is often used to instantly update the cache after submitting a form
    • After updating the cache, this will automatically call refetch() to ensure the data is correct. Disable refetch by passing an options object {refetch: false} as the second argument.
    • See the Blitz mutation usage docs for example usage of setQueryData().

Idea for improving this page? Edit it on GitHub.