
[완성된 pagination]

개인 프로젝트에서 페이지네이션을 사용해야 했는데, 원하는 기능을 포함한 라이브러리가 없어 이참에 라이브러리를 사용하지 않고 페이지네이션을 구현해보기로 했다.
[요구사항]
- 페이지가 5개씩 보여질 것.
- 페이지가 많아질 경우를 위해 제일 처음과 제일 마지막으로 가는 버튼 추가할 것.
- 5페이지에서 다음 버튼을 눌렀을 때, 다음 페이지 그룹이 보여질 것.
Props
<페이지 번호>
서버에서 내려오는 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
}
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
}
https://www.npmjs.com/package/react-pagination-lib
라이브러리를 사용하지 않고 만든 내 pagination을 오픈소스로 만들게 되었다.
아직 부족한 부분이 많지만 ㅎ-ㅎ 내 프로젝트에서 내가 만든 pagination을 사용하고 있고,
앞으로 계속 유지보수할 계획이다.