관리 메뉴

Silver Library (Archived)

Pagination, yet if you need... 본문

F2. Problem & Solving

Pagination, yet if you need...

Ayin Kim 2023. 1. 17. 22:28
반응형

Note: this post is a scrapped version of explained pagination. See the link below to read the original text.

 

Basic concept:

we need as props to our Pagination component:

  • totalCount: represents the total count of data available from the source.
  • currentPage: represents the current active page. We'll use a 1-based index instead of a traditional 0-based index for our currentPage value.
  • pageSize: represents the maximum data that is visible in a single page.
  • onPageChange: callback function invoked with the updated page value when the page is changed.
  • siblingCount (optional): represents the min number of page buttons to be shown on each side of the current page button. Defaults to 1.
  • className (optional): className to be added to the top level container.

From the pagination component we'll invoke the usePagination hook which will take in the following parameters to compute the page ranges: totalCount , currentPage , pageSize , siblingCount .

 

NOTE: this post uses usePagination hook,

  • Our pagination hook must return the range of numbers to be displayed in our pagination component as an array.
  • The computation logic needs to re-run when either  currentPage, pageSize, siblingCount, or totalCount changes.
  • The total number of items returned by the hook should remain constant. This will avoid resizing our pagination component if the length of the range array changes while the user is interacting with the component.

 let's create a file called usePagination.js in our project src folder and start with the implementation.

 

export const usePagination = ({
  totalCount,
  pageSize,
  siblingCount = 1,
  currentPage
}) => {
  const paginationRange = useMemo(() => {
     // Our implementation logic will go here 
      
  }, [totalCount, pageSize, siblingCount, currentPage]);

  return paginationRange;
};

useMemo hook is to compute core logic. This useMemo calback will run when any value in its dependency array changes.

 

Set defaultValue of our siblingCount prop to be 1 as it is an optional prop.

 

 

And surprisingly, there are types of states of a pagination component. Its four in total.

  • Total page count is less than the page pills we want to show. In such a case we just return the range from 1 to totalPageCount.
  • Total page count is greater than the page pills but only the right DOTS are visible.
  • Total page count is greater than the page pills but only the left DOTS are visible.
  • Total page count is greater than the page pills and both the left and the right DOTS are visible.

As a first step, we shall go about calculating the total pages from totalCount and pageSize  as follows:

const totalPageCount = Math.ceil(totalCount / pageSize);

Notice that we are using Math.ceil to round of the number to the next higher integer value. This ensures that we are reserving an extra page for the remaining data.

 

For more:

https://www.freecodecamp.org/news/build-a-custom-pagination-component-in-react/

 

How to Build a Custom Pagination Component in React

We often work with web applications that need to fetch large amounts of data from a server through APIs and render it on the screen. For example, in a Social media application we fetch and render users' posts and comments. In an HR dashboard we display inf

www.freecodecamp.org

 

Once it is done,

- Pagination.js file in our src folder.

Then implement the code logic as follows:

 

import React from 'react';
import classnames from 'classnames';
import { usePagination, DOTS } from './usePagination';
import './pagination.scss';
const Pagination = props => {
  const {
    onPageChange,
    totalCount,
    siblingCount = 1,
    currentPage,
    pageSize,
    className
  } = props;

  const paginationRange = usePagination({
    currentPage,
    totalCount,
    siblingCount,
    pageSize
  });

  // If there are less than 2 times in pagination range we shall not render the component
  if (currentPage === 0 || paginationRange.length < 2) {
    return null;
  }

  const onNext = () => {
    onPageChange(currentPage + 1);
  };

  const onPrevious = () => {
    onPageChange(currentPage - 1);
  };

  let lastPage = paginationRange[paginationRange.length - 1];
  return (
    <ul
      className={classnames('pagination-container', { [className]: className })}
    >
       {/* Left navigation arrow */}
      <li
        className={classnames('pagination-item', {
          disabled: currentPage === 1
        })}
        onClick={onPrevious}
      >
        <div className="arrow left" />
      </li>
      {paginationRange.map(pageNumber => {
         
        // If the pageItem is a DOT, render the DOTS unicode character
        if (pageNumber === DOTS) {
          return <li className="pagination-item dots">&#8230;</li>;
        }
		
        // Render our Page Pills
        return (
          <li
            className={classnames('pagination-item', {
              selected: pageNumber === currentPage
            })}
            onClick={() => onPageChange(pageNumber)}
          >
            {pageNumber}
          </li>
        );
      })}
      {/*  Right Navigation arrow */}
      <li
        className={classnames('pagination-item', {
          disabled: currentPage === lastPage
        })}
        onClick={onNext}
      >
        <div className="arrow right" />
      </li>
    </ul>
  );
};

export default Pagination;

We render the Pagination component as a list with left and right arrows which handle the previous and next actions the user makes. In between the arrows, we map over the paginationRange and render the page numbers as pagination-items. If the page item is a DOT we render a unicode character for it.

 

As a special handling we add a disabled class to the left/right arrow if the currentPage is the first or the last page, respectively. We disable the pointer-events and update the styles of the arrow icons through CSS if the icon needs to be disabled.

 

We also add click event handlers to the page pills which will invoke the onPageChanged callback function with the updated value of currentPage.

 

What about using custom pagination component?

https://react-1zaeqk.stackblitz.io

 

https://react-1zaeqk.stackblitz.io

 

react-1zaeqk.stackblitz.io