rhanziy

Next.js - 모바일 페이지네이션 적용(react-paginate) 본문

Next.js

Next.js - 모바일 페이지네이션 적용(react-paginate)

rhanziy 2024. 4. 22. 13:33

 

https://www.npmjs.com/package/react-paginate

 

react-paginate

A ReactJS component that creates a pagination.. Latest version: 8.2.0, last published: a year ago. Start using react-paginate in your project by running `npm i react-paginate`. There are 577 other projects in the npm registry using react-paginate.

www.npmjs.com

 

 

반응형 작업 하던 중, mui로 만든 전형적인 데스크탑 페이지네이션과 다른 ui가 필요해서 react-paginate 라이브러리를 통해

MobilePagination 컴포넌트를 만들었다.

 

기본 사용법은 쏘이지

import ReactPaginate from 'react-paginate';

const MobilePagination = ({ pageSize, totalCount }: Props) => {
  const { query, ...router } = useRouter();
  const [currentPage, setCurrentPage] = useState(0);

  useEffect(() => {
    setCurrentPage(query.pageNo ? Number(query.pageNo) - 1 : 0);
  }, [query.pageNo]);

  const handlePaginationChange = (selectedItem: { selected: number }) => {
    router.push({
      pathname: router.pathname,
      query: {
        ...query,
        pageNo: selectedItem.selected + 1,
      },
    });
  };

  return (
    <MyPaginate
      pageCount={totalCount ? Math.ceil(totalCount / pageSize) : 0}
      pageRangeDisplayed={5}
      marginPagesDisplayed={0}
      breakLabel={''}
      forcePage={currentPage}
      previousLabel={<ChevronLeftRounded />}
      nextLabel={<ChevronRightRounded />}
      onPageChange={handlePaginationChange}
      pageClassName={'pageItem'}
      activeClassName={'currentPage'}
      previousClassName={'pageLabelBtn'}
      nextClassName={'pageLabelBtn'}
    />
  );
};

 const MyPaginate = styled(ReactPaginate)`
  margin: 20px 0;
  display: flex;
  justify-content: center;
  align-items: center;
  list-style-type: none;
  padding: 10px;

  .pageItem {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 40px;
    height: 40px;
    padding: 10px;
    border-radius: 50%;
    cursor: pointer;
    text-align: center;
  }
  .currentPage {
    text-align: center;
    color: white;
    background-color: ${Palette.Primary[500]};
  }
  .pageLabelBtn {
    margin: 0 15px;
    font-size: 20px;
    color: ${Palette.GrayScale['4']};
  }

  .pageItem a {
    padding: 10px;
  }

  li.disable,
  li.disabled a {
    display: none;
  }
`;

pageCount - 페이지 총 사이즈

pageRangeDisplayed - 보여줄 page 갯수

marginPageDisplayed - 페이지 마진

breakLabel - 페이지 생략할때 표시할 라벨  1 2 3 4 ... < 이런거

forcePage - 강제로 페이지 지정 -> 아래에 서술. initialPage 옵션과 같이 사용하면 안된당.

previousLabel - 이전페이지 아이콘(나는 mui아이콘을 사용했당)

nextLabel - 다음 페이지 아이콘

onPageChange - 페이지가 변경될 때 실행할 함수

어쩌구ClassName - css 코드 작성할 때 지정할 ClassName

 

 

나는 mobilePagenation 컴포넌트에 pageSize와 totalCount를 넘겨서 코드를 구현했다.

pageCount는 total item 갯수를 pageSize로 나눠서 반올림한 값을 작성하긔. 

만약 data의 총 갯수가 20개고 한 페이지당 8개씩 보여진다면 20/8 = 3페이지로 나타내지면 되는 부분.

 

그리고 위에 useEffect 부분을 설명하자면

  const { query, ...router } = useRouter();
  const [currentPage, setCurrentPage] = useState(0);

  useEffect(() => {
    setCurrentPage(query.pageNo ? Number(query.pageNo) - 1 : 0);
  }, [query.pageNo]);

  const handlePaginationChange = (selectedItem: { selected: number }) => {
    router.push({
      pathname: router.pathname,
      query: {
        ...query,
        pageNo: selectedItem.selected + 1,
      },
    });
  };

페이지를 변경할때마다 router를 통해 페이지를 넘기고 api를 호출해서 데이터를 불러오니까

handlePaginationChange함수로 구현했고, 여기서 react paginate 는 0부터 시작하기에 +1을 해주었따.

 

근데 작동방식이 원하는대로 안되었던 부분이 뭐였냐면, 5번째 페이지에 새로고침을 하게되면 검색결과는 5페이지의 데이터인데, 페이지네이션은 1로 표시되는 문제가있었다.

 

그래서 currentPage state를 만들고 router.query(url)에서 pageNo가 있으면 해당 페이지로 force, 없으면 0 (1페이지)으로 코드를 추가해주었다. 그리고 currentPage를 forcePage 옵션에 넣어주면 원하는결과가 나왔다~

 

        {data?.totalCount > 0 && (
          <MobilePagination
            totalCount={data.totalCount}
            pageSize={data.pageSize}
          />
        )}

다른 컴포넌트에서 호출할때는 이렇게 사용.ㅇㅅㅇ 라이브러리 최고!

 

Comments