Pagination
Explore how to implement pagination in a Nuxt 3 project using the Pixabay API. Understand handling query parameters for page and per_page, managing state for images, calculating total pages, and creating navigation controls to enhance dynamic data display.
What is pagination?
Pagination is used when we have many values to organize into pages. The user can switch between these pages, and we can also set how many values we want to see on each page. A typical example is an e-commerce store where we may display 20 products per page, and the user can navigate between them.
Pagination can be handled differently depending on where our data is coming from. For our use, when using the Pixabay API, this is handled in the query string. We can pass in how many images per page we want and also the page number to fetch:
Pagination with the Pixabay API
The above example shows how we can add both the page and the per_page parameters to the query string. Since we request the first page and 10 images, we will receive images 1–10. Switching this to page two will request images 11–20.
By default, useFetch will try to cache the results to avoid making unnecessary extra requests. This means a faster user experience when a previous page is revisited.
Search example
Before we add pagination, we first need a working search example:
export default function useSearch() {
const displayImages = useDisplayImages();
const imageData = useImageData();
const config = useRuntimeConfig()
const apiKey = config.public.pixabayApiKey;
const baseUrl = "https://pixabay.com/api/";
// when term is updated from index.vue, useFetch will re-run
const searchTerm = ref("");
const { data: images } = useFetch(
() => `?key=${apiKey}&q=${searchTerm.value}`,
{
baseURL: baseUrl,
}
);
function setImageData() {
displayImages.value = [];
imageData.value = images?.value?.hits;
displayImages.value = images?.value?.hits;
}
watch(images, setImageData);
return { searchTerm };
}
The above code example has the following:
The composables/useState.js file
This has two constants for the image data which we can share throughout our app:
Line 1: The
useImageDatacontains the original, unmodified set of results from the API.Line 2: The
useDisplayImagescontains a modified set of results we can use later for filtering, etc.
The composables/useSearch.js file
This file contains all of the search-related data and functions to keep the project organized:
Lines 1–2: We store the
displayImagesandimageDatafrom our state.Line 10: The
searchTermwill causeuseFetchto run when the value changes.Line 14: We watch for the
imagesto change and run thesetImageDatafunction. This sets thedisplayImagesandimageDatato our state.
The pages/index.vue file
Lines 5–7: The
searchTermwhich is used to fetch images is updated with thehandleSearchfunction. This is set from theinputfield, which is linked to theuserInputvalue.Lines 19–21: Loop over and display and return images from the API.
Calculating the total number of pages
To make our next and previous page buttons work correctly, we need to first know how many pages we have in total. This is to avoid requesting the next page when there is no more available. We can also use this to display the total number of pages to the user.
The above code example can be used to calculate the total number of pages. We divide the number of images by the images per page, then round up to the nearest whole number. We also need to store this value inside of the state, and we can do this inside of the useState.js file:
This is how we could use it inside the useSearch.js file:
Lines 5–7: We store the image data from our
useState.jsfile.Line 18: The current page and the number of images are added to the query string,
Line 29: The number of pages is calculated each time the images change.
The previous or next page will be requested any time the query string changes. The final step is to update these values.
Putting it all together
Extending the previous example, we can see how this will look inside our project:
export default function usePagination() {
const numberOfPages = useNumberOfPages();
const currentPageNumber = useCurrentPageNumber();
function previousPage() {
if (currentPageNumber.value === 1) return;
currentPageNumber.value--;
}
function nextPage() {
if (currentPageNumber.value >= numberOfPages.value) return;
currentPageNumber.value++;
}
return { previousPage, nextPage };
}To update the pagination, a new file has been created:
Composables / usePagination.js
Lines 5–8: The
previousPagefunction checks to see if the user is on the first page and prevents this from switching to page zero if true.Lines 9–12: The
nextPagefunction also checks if the user is on the last page before moving forward to prevent any errors if no page can be found.Line 13: These two functions are returned so we can trigger them in the
index.vue.
Pages / index.vue
Lines 3: The
previousPageandnextPagefunctions are imported.Lines 31–36: Two new buttons are added to call the
previousPageandnextPagefunctions.Line 37: We display the
currentPageNumberandnumberOfPagesvalues.