convex-use-next-prev-paginated-query
v1.2.0
Published
Simple next/prev paginated query hook for Convex
Readme
useNextPrevPaginatedQuery
A React hook for paginating through a Convex paginated query result one page at a time. Works with the same query functions as Convex's usePaginatedQuery hook.
This hook keeps track of previous cursors in order to allow navigating forward and backwards through pages. It doesn't (yet) account for split pages.
Installation
npm install convex-use-next-prev-paginated-querypnpm add convex-use-next-prev-paginated-queryyarn add convex-use-next-prev-paginated-queryUsage
Use this hook with a public query that accepts a paginationOpts argument of type PaginationOptions and returns a PaginationResult, just like how the default usePaginatedQuery works. See the this page of the Convex docs for more information on how to write a well-formed paginated query function. It might look something like this:
import { v } from "convex/values";
import { query, mutation } from "./_generated/server";
import { paginationOptsValidator } from "convex/server";
export const list = query({
args: { paginationOpts: paginationOptsValidator, channel: v.string() },
handler: async (ctx, args) =>
await ctx.db
.query("messages")
.withIndex("by_channel", (q) => q.eq("channel", args.channel))
.order("desc")
.paginate(args.paginationOpts),
});Once you've defined your paginated query function, you can use it with this hook like so:
import { useNextPrevPaginatedQuery } from "convex-use-next-prev-paginated-query";
import { api } from "./_generated/api";
const MyComponent = () => {
const result = useNextPrevPaginatedQuery(
api.list,
{ channel: "general" },
{ initialNumItems: 10 }
);
if (result._tag === "Skipped") {
return <div>Skipped</div>;
} else if (result._tag === "LoadingInitialResults") {
return <div>LoadingInitialResults</div>;
} else if (result._tag === "Loaded") {
return (
<div>
<div>
{result.page.map((message) => (
<div key={message._id}>{message.text}</div>
))}
</div>
{result.loadNext && <button onClick={result.loadNext}>Next</button>}
Page {result.pageNum}
{result.loadPrev && <button onClick={result.loadPrev}>Prev</button>}
</div>
);
} else if (result._tag === "LoadingNextResults") {
return <div>LoadingNextResults</div>;
} else if (result._tag === "LoadingPrevResults") {
return <div>LoadingPrevResults</div>;
} else {
throw "Unknown state";
}
};