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

useInfiniteQuery

Topics

Jump to a Topic

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.

Example

import { useInfiniteQuery } from "@blitzjs/rpc"
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 { resolver } from "@blitzjs/rpc"
import { paginate } 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,
    }
  }
)

API

const [
  pagesOfQueryResults,
  {
    pageParams,
    fetchNextPage,
    fetchPreviousPage,
    hasNextPage,
    hasPreviousPage,
    isFetchingNextPage,
    isFetchingPreviousPage,
    ...extras
  },
] = useInfiniteQuery(queryResolver, getQueryInputArguments, {
  ...options,
  getNextPageParam: (lastPage, allPages) => lastPage.nextPage,
  getPreviousPageParam: (firstPage, allPages) => firstPage.nextPage,
})

Arguments

  • queryResolver: A Blitz query resolver
    • Required
  • getQueryInputArguments: (fetchNextPageVariable) => queryInputArguments
    • Required
    • A function that accepts the current page options and returns the queryInputArguments
    • On the first page load, fetchNextPageVariable is undefined.
    • For subsequent pages, fetchNextPageVariable is whatever is returned from getNextPageParam()
  • options
    • Optional

Options

The options are identical to the options for the useQuery hook with the addition of the following:

  • getNextPageParam: (lastPage, allPages) => unknown | undefined
    • When new data is received for this query, this function receives both the last page of the infinite list of data and the full array of all pages.
    • It should return a single variable that will be passed as the argument to getQueryInputArguments().
    • Return undefined to indicate there is no next page available.
  • getPreviousPageParam: (firstPage, allPages) => unknown | undefined
    • When new data is received for this query, this function receives both the first page of the infinite list of data and the full array of all pages.
    • It should return a single variable that will be passed as the argument to your getQueryInputArguments().
    • Return undefined to indicate there is no previous page available.

Returns

[pagesOfQueryResults, queryExtras]

pagesOfQueryResults: TData[]
  • Array containing all pages.
queryExtras: Object

The query extras for useInfiniteQuery are identical to the query extas for the useQuery hook with the addition of the following:

  • pageParams: unknown[]
    • Array containing all page params.
  • isFetchingNextPage: boolean
    • Will be true while fetching the next page with fetchNextPage.
  • isFetchingPreviousPage: boolean
    • Will be true while fetching the previous page with fetchPreviousPage.
  • fetchNextPage: (options?: FetchNextPageOptions) => Promise<UseInfiniteQueryResult>
    • This function allows you to fetch the next "page" of results.
    • options.pageParam: unknown allows you to manually specify a page param instead of using getNextPageParam.
  • fetchPreviousPage: (options?: FetchPreviousPageOptions) => Promise<UseInfiniteQueryResult>
    • This function allows you to fetch the previous "page" of results.
    • options.pageParam: unknown allows you to manually specify a page param instead of using getPreviousPageParam.
  • hasNextPage: boolean
    • This will be true if there is a next page to be fetched (known via the getNextPageParam option).
  • hasPreviousPage: boolean
    • This will be true if there is a previous page to be fetched (known via the getPreviousPageParam option).
  • setQueryData() - Function(newData, opts) => 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.