Skip to content

Latest commit

 

History

History
79 lines (65 loc) · 2.69 KB

File metadata and controls

79 lines (65 loc) · 2.69 KB

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-query
pnpm add convex-use-next-prev-paginated-query
yarn add convex-use-next-prev-paginated-query

Usage

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";
  }
};