IT/React

Pagination 구현하기

솔B 2023. 10. 17. 13:09

내가 원하던 그림!

 

Pagination component 사용 시 아래와 같이 사용한다

 

const [currentPage, setCurrentPage] = useState(1);
const [lastPage, setLastPage] = useState(0); // api 통신 후 값을 업데이트 해줌

const onChangePage = (newPage: number) => {
	setCurrentPage(newPage)
}

...
return (
	...
      <Pagination currentPage={currentPage} lastPage={lastPage} onPageChange={onChangePage} />
    ...
)


Pagination component에서는 currentPage, lastPage,  페이지를 업데이트할 수 있는 함수를 전달받는다

 

currentPage와 lastPage가 업데이트될 때마다 화면에 보여줄 페이지 리스트를 계산해 줬다 👍


page가 1페이지인 경우 더 앞으로 갈 수 없도록 앞으로 가기 버튼을 disabled 시켰고

마지막 페이지인 경우에도 뒤로 갈 수 없도록 뒤로 가기 버튼을 disabled 처리했다

 

import React, { useEffect, useState } from 'react'
import ArrowLeftIcon from 'src/assets/icon/common/ico_arrow_left.svg'
import ArrowRightIcon from 'src/assets/icon/common/ico_arrow_right.svg'
import { Spartan } from 'src/styles/mixin/mixin'
import styled from 'styled-components'

interface PaginationProps {
  currentPage: number // 현재 페이지
  lastPage: number // 마지막 페이지
  onPageChange: (page: number) => void // 현재 페이지 값을 업데이트하는 함수
}

const Pagination = ({ currentPage, lastPage, onPageChange }: PaginationProps) => {
  const DISPLAYRANGE = 5 // 화면에 보여줄 페이지의 개수

  const [pageList, setPageList] = useState<number[]>([]) // 화면에 보여줄 페이지 list

  useEffect(() => {
    setPageList([])

    const pageGroupNum = Math.ceil(currentPage / DISPLAYRANGE) // 페이지 그룹 번호

    for (
      let i = (pageGroupNum - 1) * DISPLAYRANGE + 1;
      i <= pageGroupNum * DISPLAYRANGE && i <= lastPage;
      i++
    ) {
      setPageList((prev) => [...prev, i])
    }
  }, [currentPage, lastPage]) // currentPage, lastPage가 변경될 때마다 다시 실행

  return (
    <PaginationWrapper>
      <ArrowBtn
        onClick={() => onPageChange(currentPage > 1 ? currentPage - 1 : 1)}
        disabled={currentPage === 1}
      >
        <ArrowLeftIcon fill={currentPage === 1 ? '#eee' : '#999'} width={24} height={24} />
      </ArrowBtn>
      {pageList.map((page) => (
        <PaginationBtn
          key={page}
          isActive={currentPage === page}
          onClick={() => onPageChange(page)}
        >
          <span>{page}</span>
        </PaginationBtn>
      ))}
      <ArrowBtn
        onClick={() => onPageChange(currentPage < lastPage ? currentPage + 1 : 1)}
        disabled={currentPage === lastPage}
      >
        <ArrowRightIcon fill={currentPage === lastPage ? '#eee' : '#999'} width={24} height={24} />
      </ArrowBtn>
    </PaginationWrapper>
  )
}

const PaginationWrapper = styled.div`
  display: flex;
  justify-content: center;
  gap: 32px;
  margin: 48px 0px;
`
const ArrowBtn = styled.button`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 30px;
  height: 30px;
  padding: 0px;
`
const PaginationBtn = styled.button<{ isActive: boolean }>`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 30px;
  height: 30px;
  padding: 4px;
  font-size: 16px;
  color: ${(props) =>
    props.isActive ? props.theme.colors.primaryWhite : props.theme.colors.secondaryGray2};
  background-color: ${(props) => (props.isActive ? props.theme.colors.primaryBlue : 'transparent')};
  border-radius: 100%;
  > span {
    ${[Spartan]}
  }
`

export default Pagination


이렇게 해서 만들면 잘 작동한다!

나의 경우 거의 모든 페이지에서 페이지네이션이 필요했다
Pagination component에 값을 전달해 주고 페이지 관련 내용을 상태관리 하기 위해서 (currentPage, perPage...)

많은 보일러플레이트가 만들어지고 있었다...!

다음 포스팅에서는 이를 한 번에 관리하기 위한 Pagination 관련 custom hook에 대해서 써보겠다~!

Pagination custom hook 보러가기



참고자료 - https://yonghwankim-dev.tistory.com/578