[React] 라이브러리없이 pagination 구현하기

김나연·2022년 12월 13일

React

목록 보기
2/2
post-thumbnail

[완성된 pagination]

개인 프로젝트에서 페이지네이션을 사용해야 했는데, 원하는 기능을 포함한 라이브러리가 없어 이참에 라이브러리를 사용하지 않고 페이지네이션을 구현해보기로 했다.

[요구사항]

  • 페이지가 5개씩 보여질 것.
  • 페이지가 많아질 경우를 위해 제일 처음과 제일 마지막으로 가는 버튼 추가할 것.
  • 5페이지에서 다음 버튼을 눌렀을 때, 다음 페이지 그룹이 보여질 것.

Props

  • page = 현재 페이지
  • handlePage = page 핸들러
  • totalPage = 전체 페이지 수
  • limit = 페이지네이션으로 보여질 페이지 수

[Pagination 구현 부분]

<페이지 번호>

서버에서 내려오는 page가 0부터 시작하는 것을 가정하여 작업했기 때문에 초기 배열에 [0, 1, 2, 3, 4] 5개 숫자를 담아주고,
보여줄 때 +1을 한 값을 보여준다.

onClick 이벤트로 page 핸들러에 클릭한 페이지 번호를 넘겨주면 된다.

 <button
    css={pageButtonCss}
    type="button"
    className={page === pageNumber ? 'active' : undefined}
    onClick={() => handlePage(pageNumber)}
>
    {pageNumber + 1}
</button>

<첫 페이지로 이동 버튼>

현재 페이지 page에서 0을 page 핸들러에 넘겨주면 1페이지로 이동하게 된다.
또한, 페이지가 1페이지가 되고 1페이지가 담긴 페이지 배열을 보여주기 위해 PageArray에 초기 배열 [0, 1, 2, 3, 4]를 넘겨준다.

const handleMoveFirst = () => {
        handlePage(0)
        setShowPageArray([0, 1, 2, 3, 4])
    }
<button css={arrowButtonCss} type="button" onClick={handleMoveFirst} className={prevClassName}>
	{'<<'}
</button>

<이전 페이지로 이동 버튼>

현재 페이지 page에서 -1한 값을 page 핸들러에 넘겨줌

const handlePrev = () => {
	const prevPage = page - 1
    handlePage(prevPage)
  
}
<button css={arrowButtonCss} type="button" onClick={handlePrev} className={prevClassName}>
	{'<'}
</button>

<다음 페이지로 이동 버튼>

현재 페이지 page에서 +1한 값을 page 핸들러에 넘겨줌

const handleNext = () => {
	const nextPage = page + 1
    handlePage(nextPage)
  
}
<button css={arrowButtonCss} type="button" onClick={handleNext} className={nextClassName}>
	{'>'}
</button>

<마지막 페이지로 이동 버튼>

현재 페이지 page에서 totalPage 크기만큼 page 핸들러에 넘겨주면 마지막 페이지로 이동하게 된다.
현재 페이지가 마지막 페이지가 되고 마지막 페이지가 담긴 페이지 배열을 보여주기 위해 PageArray에 마지막 페이지에 5를 뺀 값부터 5개 숫자를 넘겨준다.

const handleMoveLast = () => {
        handlePage(totalPage - 1)
        setShowPageArray(newArray(totalPage - 5))
    }
<button css={arrowButtonCss} type="button" onClick={handleMoveLast} className={nextClassName}>
	{'>>'}
</button>

<새로운 페이지 그룹을 만들어주는 함수>

5개씩 보여질 페이지 그룹에 시작 숫자를 넣으면 시작 숫자로부터 새 그룹을 만들어준다.

const newArray = (start: number) => {
        const array = []
        for (let i = start; i < start + 5; i++) {
            array.push(i)
        }
        return array
}

[Pagination을 사용한 부분]

import Pagination from '@components/Pagination'

fuction App() {
  const [page, setPage] = useState()
  const totalPage = Math.ceil(posts/20)
  
  retrun (
    <Pagination totalPage={totalPage} page={page} handlePage={handlePage} />
  )
    

한 페이지 당 20개의 데이터를 보여줄 것이기 때문에 총 데이터의 개수를 20으로 나누었다.
총 페이지의 수가 totalPage에 담기게 된다.

[ 발견된 문제점 ]

limit을 5로 설정했을때, 항상 총 페이지의 수가 5의 배수가 되지 않아 마지막 페이지의 그룹이 망가지는 것을 확인

[ 해결 ]

해결 방안 : 총 페이지 수를 limit으로 나누어 미리 배열에 담아 그룹화한다.

위처럼 구현하게 되면 예를 들어, 총 13페이지가 존재할 때 5페이지씩
[1, 2, 3, 4, 5]

[6, 7, 8, 9, 10]

[11, 12, 13]

과 같은 페이지 그룹이 만들어지고 차례대로 현재 페이지가 limit의 배수(5, 10..)일 때 다음 버튼을 누르면 페이지는 +1이 되고, 다음 페이지 그룹을 보여주게 된다.

<페이지를 그룹화하는 함수>

type GeneratePageGroupsParams = { limit: number; totalPage: number }
type GeneratePageGroups = (params: GeneratePageGroupsParams) => number[][]

const generatePageGroups: GeneratePageGroups = ({ limit, totalPage }) => {
    const pageGroups = []
    const totalPageGroup = Math.ceil(totalPage / limit)
    for (let pageGroup = 1; pageGroup <= totalPageGroup; pageGroup++) {
        const tmp = []
        const start = (pageGroup - 1) * limit
        const end = Math.min(start + limit, totalPage)
        for (let page = start; page < end; page++) {
            tmp.push(page)
        }
        pageGroups.push(tmp)
    }

    return pageGroups
}

[pagination 전체코드 보러 가기]

https://www.npmjs.com/package/react-pagination-lib

라이브러리를 사용하지 않고 만든 내 pagination을 오픈소스로 만들게 되었다.
아직 부족한 부분이 많지만 ㅎ-ㅎ 내 프로젝트에서 내가 만든 pagination을 사용하고 있고,
앞으로 계속 유지보수할 계획이다.

profile
결국 무엇이든 해내는 사람 '김나연'입니다. 😎

0개의 댓글