Examples
This page shows a live demo and code snippets.
Live Demo
ID Cursor (basic)
import { CursorPagination, useCursorPagination } from 'react-cursor-pagination';
type Item = { id: number; name: string };
async function fetchItems(cursor?: number) {
const res = await fetch(`/api/items?cursor=${cursor ?? ''}`);
return (await res.json()) as { items: Item[]; nextCursor?: number };
}
export default function Example() {
const paginationKey = 'example';
const { currentCursor } = useCursorPagination<number>(paginationKey);
const [items, setItems] = useState<Item[]>([]);
const [nextCursor, setNextCursor] = useState<number | undefined>();
useEffect(() => {
fetchItems(currentCursor).then((page) => {
setItems(page.items);
const last = page.items[page.items.length - 1];
setNextCursor(last ? last.id : undefined);
});
}, [currentCursor]);
return (
<div>
{items.map((x) => (
<div key={x.id}>{x.name}</div>
))}
<CursorPagination paginationKey={paginationKey} nextCursor={nextCursor} />
</div>
);
}
Session persistence
const key = 'users';
const { currentCursor } = useCursorPagination<string>(key, { persist: 'session' });
// fetch with currentCursor...
// render <CursorPagination paginationKey={key} nextCursor={nextCursor} />
Custom Pagination UI
function MyPagination<T>({ nextCursor, paginationKey }: { nextCursor?: T; paginationKey: string }) {
const { currentPage, addNextCursor, removeLastCursor, removeAllCursors, cursors } = useCursorPagination<T>(paginationKey);
return (
<div>
<button onClick={removeAllCursors} disabled={cursors.length === 0}>First</button>
<button onClick={removeLastCursor} disabled={cursors.length === 0}>Prev</button>
<span>Page {currentPage}</span>
<button onClick={() => addNextCursor(nextCursor)} disabled={!nextCursor}>Next</button>
</div>
);
}
Composite cursor (age + id)
import { CursorPagination, useCursorPagination } from 'react-cursor-pagination';
type Item = { id: number; age: number; name: string };
type AgeIdCursor = { age: number; id: number };
async function fetchItems(cursor?: AgeIdCursor): Promise<{ items: Item[] }> {
const params = cursor ? `?age=${cursor.age}&id=${cursor.id}` : '';
const res = await fetch(`/api/items${params}`);
return res.json();
}
export default function AgeIdExample() {
const paginationKey = 'age-id';
const { currentCursor } = useCursorPagination<AgeIdCursor>(paginationKey);
const [items, setItems] = useState<Item[]>([]);
const [nextCursor, setNextCursor] = useState<AgeIdCursor | undefined>();
useEffect(() => {
fetchItems(currentCursor).then((page) => {
setItems(page.items);
const last = page.items[page.items.length - 1];
setNextCursor(last ? { age: last.age, id: last.id } : undefined);
});
}, [currentCursor]);
return (
<div>
{items.map((x) => (
<div key={`${x.age}-${x.id}`}>{x.name} (age: {x.age})</div>
))}
<CursorPagination paginationKey={paginationKey} nextCursor={nextCursor} />
</div>
);
}
Note: The backend should sort by age ASC, id ASC
and filter with the same composite condition to ensure stable pagination.