Skip to content

Paging

Arc supports server-side paging for query proxies when the backend query returns IQueryable<T>.

When the backend returns IQueryable<T>, the query pipeline applies .Skip() and .Take() on the server so only the requested page is fetched. Generated proxies expose useWithPaging and useSuspenseWithPaging for this flow.

For backend implementation details, see Controller-based Paging and Model-bound Paging.

Use useWithPaging instead of use, passing a page size:

export const AccountList = () => {
const [result, perform, setSorting, setPage, setPageSize] = AllAccounts.useWithPaging(25);
return (
<>
<DataTable value={result.data}>
<Column field="name" header="Name" />
<Column field="balance" header="Balance" />
</DataTable>
<p>
Page {result.paging.page + 1} of {result.paging.totalPages}
({result.paging.totalItems} total items)
</p>
<button
disabled={result.paging.page === 0}
onClick={() => setPage(result.paging.page - 1)}>
Previous
</button>
<button
disabled={result.paging.page >= result.paging.totalPages - 1}
onClick={() => setPage(result.paging.page + 1)}>
Next
</button>
</>
);
};

useWithPaging returns an extended tuple:

IndexNameTypeDescription
0resultQueryResultWithState<T>Query result including paging metadata
1perform() => Promise<void>Re-execute the query
2setSorting(sorting: Sorting) => Promise<void>Change sort field and direction
3setPage(page: number) => Promise<void>Navigate to a specific page (zero-based)
4setPageSize(pageSize: number) => Promise<void>Change number of items per page

Paging information is available on result.paging:

PropertyTypeDescription
pagenumberCurrent zero-based page number
sizenumberItems per page
totalItemsnumberTotal items across all pages
totalPagesnumberTotal number of pages
HookDescription
MyQuery.useWithPaging(pageSize)Standard query with paging
MyQuery.useSuspenseWithPaging(pageSize)Suspense-compatible query with paging
MyObservableQuery.useWithPaging(pageSize)Observable query with paging

Each variant accepts optional args and optional sorting.

Sorting is independent of paging and works with all query hooks.

import { Sorting, SortDirection } from '@cratis/arc/queries';
// Initial sorting
const [result] = AllAccounts.use(undefined, new Sorting('name', SortDirection.ascending));
// Change sorting dynamically
const [paged, perform, setSorting] = AllAccounts.useWithPaging(25);
await setSorting(new Sorting('balance', SortDirection.descending));

Automatic paging requires the backend to return IQueryable<T>. If the backend returns IEnumerable<T> or List<T>, paging parameters are sent but ignored, and all rows are returned in one response.