useInfiniteQuery

info
  • Your procedure needs to accept a cursor input of any type
  • For more details on infinite queries read the react-query docs
  • In this example we’re using Prisma - see their docs on cursor-based pagination

Example Procedure

server/routers/_app.ts

  1. import * as trpc from '@trpc/server';
  2. import { Context } from './[trpc]';
  3. export const appRouter = trpc.router<Context>()
  4. .query('infinitePosts', {
  5. input: z.object({
  6. limit: z.number().min(1).max(100).nullish(),
  7. cursor: z.number().nullish(), // <-- "cursor" needs to exist, but can be any type
  8. }),
  9. async resolve({ input }) {
  10. const limit = input.limit ?? 50;
  11. const { cursor } = input;
  12. const items = await prisma.post.findMany({
  13. take: limit + 1, // get an extra item at the end which we'll use as next cursor
  14. where: {
  15. title: {
  16. contains: 'Prisma' /* Optional filter */,
  17. },
  18. },
  19. cursor: cursor ? { myCursor: cursor } : undefined,
  20. orderBy: {
  21. myCursor: 'asc',
  22. },
  23. })
  24. let nextCursor: typeof cursor | null = null;
  25. if (items.length > limit) {
  26. const nextItem = items.pop()
  27. nextCursor = nextItem!.myCursor;
  28. }
  29. return {
  30. items,
  31. nextCursor,
  32. };
  33. })

Example React Component

components/MyComponent.tsx

  1. import { trpc } from '../utils/trpc';
  2. export function MyComponent() {
  3. const myQuery = trpc.useInfiniteQuery(
  4. [
  5. 'infinitePosts',
  6. {
  7. limit: 10,
  8. },
  9. ],
  10. {
  11. getNextPageParam: (lastPage) => lastPage.nextCursor,
  12. },
  13. );
  14. // [...]
  15. }

Helpers

getInfiniteQueryData()

This helper gets the currently cached data from an exisisting infinite query

components/MyComponent.tsx

  1. import { trpc } from '../utils/trpc';
  2. export function MyComponent() {
  3. const utils = trpc.useContext();
  4. const myMutation = trpc.useMutation('infinitePosts.add', {
  5. onMutate({ post }) {
  6. await utils.cancelQuery(['infinitePosts']);
  7. const allPosts = utils.getInfiniteQueryData(['infinitePosts', { limit: 10 }]);
  8. // [...]
  9. }
  10. })
  11. }

setInfiniteQueryData()

This helper allows you to update a queries cached data

components/MyComponent.tsx

  1. import { trpc } from '../utils/trpc';
  2. export function MyComponent() {
  3. const utils = trpc.useContext();
  4. const myMutation = trpc.useMutation('infinitePosts.delete', {
  5. onMutate({ post }) {
  6. await utils.cancelQuery(['infinitePosts']);
  7. utils.setInfiniteQueryData(['infinitePosts', { limit: 10 }], (data) => {
  8. if (!data) {
  9. return {
  10. pages: [],
  11. pageParams: []
  12. }
  13. }
  14. return {
  15. ...data,
  16. pages: data.pages.map((page) => {
  17. ...page,
  18. items: page.items.filter((item) => item.status === 'published')
  19. })
  20. }
  21. });
  22. }
  23. });
  24. // [...]
  25. }