Pagination
Pagination are usually visible to user in the bottom of some websites such as search engines have them in the bottom. The purpose is to not show all results as they would take forever to load.
I always paginate because it makes requests small and fast. Another reason to always paginate is that if the data grows too big then it is easier to keep using pagination. Yes, I made the horrible mistake in past and they got too hard to change!
Requirements
Every pagination implementation should have the following:
- current page number
- total pages
- way to limit size
API Paginated Response
Choose one format on always follow that one, such as following JsonApi specification. Below is what I prefer, I usually don't use "next" and "previous" urls because I prefer having flexible frontend.
{
"data": [{ "id": "cake_1" }, { "id": "cake_2" }],
"meta": {
"previous": 2,
"current": 3,
"next": 4,
"pages": 8,
"size": 2
}
}
The page navigation then happens with query params /v1/cakes?page=3&size=2
.
Using Paginated Response in Frontend
Below is an example implementation in React, if last and first page is needed just load page 1 or pages.
const Pagination = props => {
const {
data: { meta },
setData,
url,
urlParams = {},
} = props
const [currentPage, setCurrentPage] = useState()
const loadPage = pageNumber => {
const params = new URLSearchParams({
...urlParams,
page: pageNumber,
size: meta.size,
})
const apiUrl = url + params.toString()
fetch(apiUrl).then(response => {
response.json().then(data => setData(data))
})
}
return (
<div>
<span onClick={() => loadPage(currentPage - 1)}>Previous</span>
<span>
{currentPage} / {meta.pages}
</span>
<span onClick={() => loadPage(currentPage + 1)}>Next</span>
</div>
)
}
Usually one needs to also be able to refetch the data from parent component. In this case, the parent component need to construct the URL with searchParams and taking pagination metadata in account. I recommend to implementing an url construction function or hook so it is reusable.