T
TanStack3y ago
adverse-sapphire

I can't, for the life of me, get `getPreviousPageParam` to work

I'm trying to use useInfiniteQuery to create a simple paginated component that shows the results of the CURRENT page and allows to paginate back and forth with left/right buttons. My REST API (DRF) is using the limit/offset approach rather than page/size, which may be related to the issue I'm having. To speed things up, I created a wrapper hook that simply allows me to specify the base URL and take care of the rest. Here's the code:
import { useInfiniteQuery, type UseInfiniteQueryOptions } from "@tanstack/react-query";
import api from "../lib/api";
import { django } from "../lib/settings";
import type { PaginatedResponse } from "../types/api";

export interface UseAPIPaginationOptions<T = any> extends Omit<UseInfiniteQueryOptions<PaginatedResponse<T>>, "queryFn" | "getNextPageParam"> {
queryKey: NonNullable<UseInfiniteQueryOptions["queryKey"]>;
}

type Offset = number | undefined;

export const useAPIPagination = <T = any>(url: string, c: UseAPIPaginationOptions<T>) => {
const { queryKey, ...r } = c;

return useInfiniteQuery({
...r,
queryKey,

queryFn: async ({ pageParam }: { pageParam?: Offset }) => {
return api
.get<PaginatedResponse<T>>(url, {
params: {
[django.PAGINATION.LIMIT_PARAM]: django.PAGINATION.PAGE_SIZE,
...(pageParam && { [django.PAGINATION.OFFSET_PARAM]: pageParam }),
},
})
.then((res) => res.data);
},

getPreviousPageParam: (firstPage): Offset => {
// ???
},

getNextPageParam: (lastPage): Offset => {
if (lastPage.next) {
const offsetValue = new URL(lastPage.next).searchParams.get(
django.PAGINATION.OFFSET_PARAM
);

if (offsetValue) {
return Number(offsetValue);
}
}

return undefined;
},
});
};
import { useInfiniteQuery, type UseInfiniteQueryOptions } from "@tanstack/react-query";
import api from "../lib/api";
import { django } from "../lib/settings";
import type { PaginatedResponse } from "../types/api";

export interface UseAPIPaginationOptions<T = any> extends Omit<UseInfiniteQueryOptions<PaginatedResponse<T>>, "queryFn" | "getNextPageParam"> {
queryKey: NonNullable<UseInfiniteQueryOptions["queryKey"]>;
}

type Offset = number | undefined;

export const useAPIPagination = <T = any>(url: string, c: UseAPIPaginationOptions<T>) => {
const { queryKey, ...r } = c;

return useInfiniteQuery({
...r,
queryKey,

queryFn: async ({ pageParam }: { pageParam?: Offset }) => {
return api
.get<PaginatedResponse<T>>(url, {
params: {
[django.PAGINATION.LIMIT_PARAM]: django.PAGINATION.PAGE_SIZE,
...(pageParam && { [django.PAGINATION.OFFSET_PARAM]: pageParam }),
},
})
.then((res) => res.data);
},

getPreviousPageParam: (firstPage): Offset => {
// ???
},

getNextPageParam: (lastPage): Offset => {
if (lastPage.next) {
const offsetValue = new URL(lastPage.next).searchParams.get(
django.PAGINATION.OFFSET_PARAM
);

if (offsetValue) {
return Number(offsetValue);
}
}

return undefined;
},
});
};
But I don't understand how getPreviousPageParam would work. How would having the first page only be useful? Maybe I'm adopting the wrong approach. Thanks!
2 Replies
absent-sapphire
absent-sapphire3y ago
I wouldn't use useInfiniteQuery for this as you're just showing one page at a time, so it sounds more like a regular paginated query rather than an infinite query: https://tanstack.com/query/v4/docs/react/guides/paginated-queries
Paginated / Lagged Queries | TanStack Query Docs
Rendering paginated data is a very common UI pattern and in TanStack Query, it "just works" by including the page information in the query key:
adverse-sapphire
adverse-sapphireOP3y ago
Thanks Julien!

Did you find this page helpful?