nextjs tailwind pagination 컴포넌트 (usePagination)
nextjs에서 tailwind를 사용하여 pagination 컴포넌트 만들기
usePagination 훅
// /lib/hooks/usePagination.ts
type NumberOrEllipsis = number | '...'
type NumberOrEllipsisArray = NumberOrEllipsis[]
const usePagination = ({
currentPage,
totalPages,
}: {
currentPage: number
totalPages: number
}): NumberOrEllipsisArray => {
const pages: NumberOrEllipsisArray = [1]
if (totalPages <= 5) {
for (let i = 2; i < totalPages; i++) {
pages.push(i)
}
} else if (currentPage <= 3) {
pages.push(2, 3, '...')
} else if (currentPage > totalPages - 3) {
pages.push('...', totalPages - 2, totalPages - 1)
} else {
pages.push('...', currentPage, '...')
}
pages.push(totalPages)
return pages
}
export default usePagination
Pagination 컴포넌트
'use client'
import React, { useCallback } from 'react'
import { Button } from './ui/button'
import {
DotsThree,
CaretLeft,
CaretRight,
} from '@phosphor-icons/react/dist/ssr'
import { usePathname, useSearchParams } from 'next/navigation'
import Link from 'next/link'
import usePagination from '@/lib/hooks/usePagination'
interface PaginationProps {
page: number
totalPages: number
}
const Pagination = ({ page, totalPages }: PaginationProps) => {
const pathname = usePathname()
const searchParams = useSearchParams()
const pages = usePagination({ currentPage: page, totalPages })
// url 생성
const getNewUrl = useCallback(
(page: number) => {
const params = new URLSearchParams(searchParams)
params.set('page', page.toString())
return `${pathname}?${params.toString()}`
},
[pathname, searchParams]
)
// 이전페이지, 다음페이지 버튼 링크
const getNavButton = useCallback(
(direction: 'left' | 'right') => {
const isLeft = direction === 'left'
const disabled = isLeft ? page <= 1 : page >= totalPages
const Icon = isLeft ? CaretLeft : CaretRight
const newPage = isLeft ? page - 1 : page + 1
return (
<Button
variant='ghost'
size='icon'
disabled={disabled}
asChild={!disabled}
>
{disabled ? (
<Icon size={28} className='text-muted-foreground' />
) : (
<Link href={getNewUrl(newPage)}>
<Icon size={28} className='text-muted-foreground' />
</Link>
)}
</Button>
)
},
[getNewUrl, page, totalPages]
)
return (
<div className='flex justify-center space-x-2 items-center'>
{getNavButton('left')}
{pages.map((p) => {
if (p === '...') {
return (
<DotsThree key={p} size={30} className='text-muted-foreground' />
)
}
return (
<Button key={p} variant={p === page ? 'secondary' : 'ghost'} asChild>
<Link href={getNewUrl(p)}>{p}</Link>
</Button>
)
})}
{getNavButton('right')}
</div>
)
}
export default Pagination
'JAVASCRIPT' 카테고리의 다른 글
vitest에서 msw를 사용해 api mocking 시작하기 (0) | 2024.02.08 |
---|---|
Firebase에서의 on the fly 방식 썸네일 이미지 최적화(Hosting, Cloud functions) (0) | 2024.01.24 |
nextjs middleware rewrite를 통해 서브 도메인 적용하기 (0) | 2023.11.26 |
항해 플러스 코육대 1회 총알 피하기가 아니라 추석 음식 피하기! 회고 (1) | 2023.10.03 |
최종 프로젝트 종료와 코드 리뷰 회고 (0) | 2023.09.19 |