Pagination

Published:

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.