Skip to Content
Docs
GraphQL
Infinite Query Hooks

Infinite Query Hooks

“Infinite” queries provide an extra layer of functionality on top of regular query hooks, to provide “load more” functionality on queries which are likely to return a lot of results.

WPGraphQL uses the Relay specification, which prefers to use a “cursor” (the ID of the last object), rather than the traditional “page number” approach — making it harder to build more traditional numbered pagination systems, but easier to build “load more” style pagination systems. You can read more about the justification for this here .

Any query which has Infinite in the name (eg. UseInfinitePosts) will be automatically generated as an infinite query hook. The query file naming conventions still applies to infinite queries.

Hook API

These hooks work just like regular query hooks, but have some extra properties available:

type UseInfiniteQuery<T> = UseQuery<T> & { /** * Will be `true` if there is a next page to be fetched (known via the `getNextPageParam` option). */ hasNextPage: boolean; /** * Will be `true` while fetching the next page with `fetchNextPage`. */ isFetchingNextPage: boolean; /** * This function allows you to fetch the next "page" of results. */ fetchNextPage: () => void }

Requirements

There are a few special requirements for infinite hooks, but we’ve configured the dev tooling to warn you if you’re not following these conventions (on top of the usual naming convention requirements)

Query Requirements:

  • The query name must contain the word ‘Infinite’ (eg. UseInfinitePosts)
  • There must be a $limit: Int variable defined on the query, with a default value. This is the number of items to load per page.
  • There must be a $cursor: String variable defined on the query, with no default value. This is used for controlling pagination.
  • The $cursor variable must be used in the after field of the query.
  • The $limit variable must be used in the first field of the query.
  • Your query must select nodes
  • Your query must select the endCursor and hasNextPage fields from the pageInfo object

Example Usage

Here’s an example query which fits all of those requirements (it’s pretty simple!):

queries/UseInfinitePosts.graphql
query UseInfinitePosts($limit: Int = 6, $cursor: String) { posts(first: $limit, after: $cursor) { pageInfo { endCursor hasNextPage } nodes { uri title } } }

Unlike regular queries, the data property will not contain the full result — but will instead be an object with nodes (an array of results, built from all the pages loaded so far), and an optional total (if selected and supported, which will be the total results available).

To built a complete UI, you should also render a “load more” button if hasNextPage is true, and call loadNextPage() when the button is clicked. Alternatively, you can achieve an infinite-scroll UI, similar to Instagram/Facebook/Twitter by using an intersection observer sensor instead of a button. Heres’ an example component which uses the query above:

components/LatestPosts.tsx
import { useInfinitePosts } from "@hooks/queries" function InfiniteExample() { const lookup = useInfinitePosts() return ( <div> {/* The initial load is in progress, show some loading indicator */} {lookup.isLoading && <div>Loading...</div>} {/* The list of items, which will grow as more items are loaded */} {lookup.isSuccess &&<ul> {lookup.data?.nodes?.map((item, key) => { return <li key={key}>{item.title}</li> })} </ul>} {/* A 'Load more' button, which is disabled and shows 'Loading...' when more items are loading */} {posts.hasNextPage && ( <button disabled={posts.isFetchingNextPage} onClick={() => posts.fetchNextPage()}> {posts.isFetchingNextPage ? "Loading..." : "Load more"} </button> )} </div> ) }
Last updated on