Paginated Query
For paginated queries, you only need the queryById utilities. You may also use the insertPaginationPlaceholderData that will display the previous page data during the new page loading. See more about insertions in insertions section.
Simple Example
const userListStore = signalStore(
withProps(() => ({
api: inject(ApiService),
})),
withState({
page: 1,
}),
withQueryById('users', (store) =>
rxQueryById(
{
params: store.page,
identifier: (params) => params,
stream: ({ params: page }) =>
store.api.getDataList$({
page: page,
pageSize: 4,
}),
},
// 👇 Use it to display the previous page data during the incoming page loading
// It also expose currentPageData / currentPageStatus / isPlaceholderData
insertPaginationPlaceholderData
)
),
withMethods((store) => ({
nextPage: () =>
patchState(store, (state) => ({
page: state.page + 1,
})),
previousPage: () =>
patchState(store, (state) => ({
page: state.page - 1,
})),
}))
);
// usage
userListServerStateStore2.usersQueryById.currentPageData; // Signal<User[] | undefined>Advanced pagination
In the simple example, the list is only drive by the page number, no sorting, no custom page size... But when adding sorting, custom page size... their is more works todo and it is not straightforward.
This project is new, but maybe an insertion can help to simplify this case. Let me know if you have interesting ideas
For this advanced pagination, we will make example based on this pagination state:
// ...
const advancedPaginationStore = signalStore(
withState({
pagination: {
page: 1,
pageSize: 4,
},
}),
withQueryById('users', (store) =>
queryById(
{
params: store.pagination,
// ...
},
insertPaginationPlaceholderData
)
)
// ...
);Their is two way, I think to deal with advanced pagination.
WARNING
- Make sur to understand the link between the
paramsand theidentifier, that will generate the pagination Map key(generated by the identifier)/pageValue (that is a represented by a resource). - And the
equalParamsoption.
Case one: Handle it with equalParams
const advancedPaginationStore = signalStore(
withState({
pagination: {
page: 1,
pageSize: 4,
},
}),
withQueryById('users', (store) =>
queryById(
{
params: store.pagination,
identifier: (params) => params.page,
equalParams: (a, b) => a.page === b.page && a.pageSize === b.pageSize,
// ...
},
insertPaginationPlaceholderData
)
)
// ...
);Here what is does:
- The
identifier: (params) => params.page,will index all the pages value by the page number : Map<PageNumber, PageValue> - The
equalParams: (a, b) => a.page === b.page && a.pageSize === b.pageSizewill be used when accessing to the current page resource asequalparameter.
Why using the equalParams ?
- Each page value is represented by a
resource, of which the params is the global params duqueryById=>params: store.pagination,. - Now, imagine you change to the next page, then go back to the previous page.
- The global params will be:
{page: 1, pageSize: 4}/{page: 2, pageSize: 4}/{page: 1, pageSize: 4} - But each time the page change, the reference will surely change, that means the corresponding resource will load again, whereas the resource params are equals.
- This is why
equalParamscan be useful, to only reload an existing page if the params really change
Case two: Advanced identifier
To solve the same problem (avoiding to reload the same page when the pagination values are the same), it is possible to use a custom identifier.
const advancedPaginationStore = signalStore(
withState({
pagination: {
page: 1,
pageSize: 4,
},
}),
withQueryById('users', (store) =>
queryById(
{
params: store.pagination,
identifier: (params) => `${params.page}-${params.pageSize}`,
// ...
},
insertPaginationPlaceholderData
)
)
// ...
);Here what is does:
- Will generate a new
resourcewith associated his custom identifier for each pagination combination
Example
Check the List with pagination example in the examples section