Add pagination to your Faust.js site
This guide covers how to set up Pagination in your Faust.js site with Apollo and WPGraphQL.
Setup
// RelayStylePagination.js
import { relayStylePagination } from "@apollo/client/utilities";
export class RelayStylePaginationPlugin {
apply(hooks) {
const { addFilter } = hooks;
addFilter("apolloClientInMemoryCacheOptions", "faust", (options) => {
return {
...options,
typePolicies: {
...options.typePolicies,
RootQuery: {
...options.typePolicies.RootQuery,
fields: {
posts: relayStylePagination(),
},
},
ContentType: {
fields: {
contentNodes: relayStylePagination(),
},
},
},
};
});
}
}
Code language: JavaScript (javascript)
The Apollo client can implement relay-style pagination with the relay spec using merge and read functions, which means all the details of connections
, edges
and pageInfo
can be abstracted away, into a single, reusable helper function. WPGraphQL follows the relay spec as well.
We are importing the relayStylePagination
function from Apollo and then a class component
is created which is the basic syntax of the Faust plugin.
Next, we have an apply
method with the hooks
parameter which is an object that gives you a function called addFilter
. The addFilter
function allows us to modify the Apollo Client’s InMemoryCacheOptions
.
The addFilter
hook is taken and calls the memory cache function options. The options are coming from the Apollo Client Cache configuration. These options allow for configuring the cache for pagination. The faust namespace follows that.
Register the Plugin for Pagination
NOTE: experimentalPlugins
is being deprecated and replaced with plugins
in the faust.config.js
file. Please update your configuration accordingly.
Import and register your plugin for pagination in faust.config.js
by adding it to the plugins
array:
import { setConfig } from "@faustwp/core";
import templates from "./wp-templates";
import possibleTypes from "./possibleTypes.json";
import { RelayStylePaginationPlugin } from "./plugins/RelayStylePagination";
/**
* @type {import('@faustwp/core').FaustConfig}
**/
export default setConfig({
templates,
plugins: [new RelayStylePagination()],
possibleTypes,
});
Code language: JavaScript (javascript)
Example WPGraphQL Pagination Query
This is an example of a query with the fields for pagination being hasNextPage
and endCursor
:
const GET_POSTS = gql`
query getPosts($first: Int!, $after: String) {
posts(first: $first, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
id
databaseId
title
slug
}
}
}
}
`;
Code language: PHP (php)
How to query for your paginated data
Now that you have your query with paginantion setup, Apollo provides a fetchMore
helper function along with the useQuery
hook to assist with fetching paginated queries. This enables you to execute the same query with different values for varibles like the current cursor and the batch size number of posts you want to grab.
Go to the components directory of your Faust project and create a file. For this guide, let’s call it LoadMorePost.js
, and insert this content:
import { useQuery, gql } from "@apollo/client";
import Link from "next/link";
const GET_POSTS = gql`
query getPosts($first: Int!, $after: String) {
posts(first: $first, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
id
databaseId
title
slug
}
}
}
}
`;
const BATCH_SIZE = 5;
export default function LoadMorePost() {
const { data, loading, error, fetchMore } = useQuery(GET_POSTS, {
variables: { first: BATCH_SIZE, after: null },
});
console.log(data);
if (error) {
return <p>Sorry, an error happened. Reload Please</p>;
}
if (!data && loading) {
return <p>Loading...</p>;
}
if (!data?.posts.edges.length) {
return <p>no posts have been published</p>;
}
const posts = data.posts.edges.map((edge) => edge.node);
const haveMorePosts = Boolean(data?.posts?.pageInfo?.hasNextPage);
return (
<>
<ul style={{ padding: "0" }}>
{posts.map((post) => {
const { databaseId, title, slug } = post;
return (
<li
key={databaseId}
style={{
border: "2px solid #ededed",
borderRadius: "10px",
padding: "2rem",
listStyle: "none",
marginBottom: "1rem",
}}
>
<Link href={`${slug}`}>{title}</Link>
</li>
);
})}
</ul>
{haveMorePosts ? (
<form
method="post"
onSubmit={(event) => {
event.preventDefault();
fetchMore({ variables: { after: data.posts.pageInfo.endCursor } });
}}
>
<button type="submit" disabled={loading}>
{loading ? "Loading..." : "Load more"}
</button>
</form>
) : (
<p>✅ All posts loaded.</p>
)}
</>
);
}
Code language: JavaScript (javascript)
Once gql
and useQuery
are imported at the top of the file coming from Apollo, That allows you to use those helpers in the file. We called our query GET_POSTS
and we are passing that in with the useQuery
hook.
The variables I have set are batch size
which are defined to be 5
and after null
which tells the query to start from the beginning of the batch. This function gets fired off each time a use clicks the load more
button.
The onSubmit
handler in this guide example calls the fetchMore
function in Apollo and passes that variable called after that grabs the current end cursor whcih is the unique ID that represents the last post in the data set to grab the next 5
after that end cursor.
Lastly, do not forget to run npm run generate
since the schema was updated with WPGraphQL and Pagination. You should now be able to query for cursor based paginated content in your Faust.js site.
Once this is all done, to make sure it is working, go to the pages
directory in the root of the Faust project, and create a file. Let’s call it pagination.js
. Insert this content:
import Head from "next/head";
import LoadMorePost from "../components/LoadMorePost";
export default function LoadMore() {
return (
<>
<Head>
<title>Load More</title>
</Head>
<main>
<h1>Load More Example</h1>
<LoadMorePost />
</main>
</>
);
}
Code language: JavaScript (javascript)
This is the component we are using in this page file to render our paginated post. Once this is all done, visit http://localhost:3000/pagination
after running your dev server and you should see your paginated post!
If you need an in depth start to finish article with an example, please visit the developer relations article on working with Apollo in Faust.js.