import { useState, useCallback } from "react";
interface UsePaginationOptions {
pageSize?: number;
}
function usePagination<T>(endpoint: string, options: UsePaginationOptions = {}) {
const { pageSize = 20 } = options;
const [data, setData] = useState<T[]>([]);
const [pageInfo, setPageInfo] = useState<PageInfo | null>(null);
const [loading, setLoading] = useState(false);
const fetchPage = useCallback(
async (cursor?: string, direction: "forward" | "backward" = "forward") => {
setLoading(true);
try {
const params = new URLSearchParams();
if (direction === "forward") {
params.set("first", String(pageSize));
if (cursor) params.set("after", cursor);
} else {
params.set("last", String(pageSize));
if (cursor) params.set("before", cursor);
}
const response = await fetch(`${endpoint}?${params}`);
const result: PaginatedResponse<T> = await response.json();
setData(result.data);
setPageInfo(result.pageInfo);
} finally {
setLoading(false);
}
},
[endpoint, pageSize]
);
const nextPage = useCallback(() => {
if (pageInfo?.endCursor) {
fetchPage(pageInfo.endCursor, "forward");
}
}, [pageInfo, fetchPage]);
const prevPage = useCallback(() => {
if (pageInfo?.startCursor) {
fetchPage(pageInfo.startCursor, "backward");
}
}, [pageInfo, fetchPage]);
return {
data,
pageInfo,
loading,
fetchPage,
nextPage,
prevPage,
hasNextPage: !!pageInfo?.endCursor,
hasPrevPage: !!pageInfo?.startCursor,
};
}