진행하고 있는 프로젝트에서 유기견 공고를 받아와서 목록으로 보여주는데 페이지네이션을 사용하기로 했다.
나는 1페이지에 각 15개의 공고를 보여주고자 했고 아래와 같이 구현했다.
const StrayDogs = () => {
const [selectCity, setSelectCity] = useState('');
//페이지 번호
const [page, setPage] = useState(1);
// 한 페이지에 보여주고자 하는 데이터 수
const limit = 15;
const offset = (page - 1) * limit;
// 받아온 유기견 정보
const {
isLoading,
isError,
data: strayList
} = useQuery<StrayList[]>({
queryKey: ['strayList'],
queryFn: getStrayList,
refetchOnWindowFocus: false,
staleTime: 3000
});
if (isLoading) {
return <Loading />;
}
if (isError) {
return <div>🙇🏻♀️오류가 발생하였습니다🙇🏻♀️</div>;
}
// 유기견 공고 목록
return (
<div className={style.container}>
<div className={style.gridContainer}>
{strayList?.slice(offset, offset + limit).map((list, index) => {
const formatNoticeEdt = formatDate(list.noticeEdt);
return (
<div key={index} className={style.listContainer}>
<Link href={`/stray-dogs/${list.desertionNo}`}>
<div className={style.listCard}>
<Image
src={list.popfile}
alt="dog-image"
className={style.image}
width={250}
height={250}
/>
<div className={style.explanationWrap}>
<div className={style.titleColumn}>
<p>
<FaCalendarDays />
공고기간
</p>
<p>
<FaDog />
견종
</p>
<p>
<PiGenderIntersexFill />
성별
</p>
<p>
<FaMapMarkerAlt />
발견장소
</p>
</div>
<div className={style.contentColumn}>
<p>{formatNoticeEdt} 까지</p>
<p>{list.kindCd.slice(3)}</p>
<p>{list.sexCd === 'M' ? '수컷' : '암컷'}</p>
<p>{list.happenPlace}</p>
</div>
</div>
</div>
</Link>
</div>
);
})}
</div>
// 페이지네이션 컴포넌트
<Pagination page={page} setPage={setPage} limit={limit} total={strayList?.length} />
</div>
);
};
페이지 번호, 보여주고자 하는 데이터 수를 state로 만들어주고 offset과 같은 식을 만든 후 페이지네이션 컴포넌트에 props로 내려준다.
Pagination.tsx
function Pagination({ page, setPage, total, limit }: Props) {
const numPages = Math.ceil(total! / limit);
const pagesToShow = 5;
const startPage = Math.max(1, page - Math.floor(pagesToShow / 2));
const endPage = Math.min(numPages, startPage + pagesToShow - 1);
const renderPageButtons = Array.from(
{ length: endPage - startPage + 1 },
(_, index) => startPage + index
);
return (
<nav className={style.buttonWrapper}>
<button
className={style.button}
onClick={() => setPage(Math.max(1, page - pagesToShow))}
disabled={page <= 1}
>
<
</button>
{renderPageButtons.map((pageNumber) => (
<button
key={pageNumber}
onClick={() => setPage(pageNumber)}
className={page === pageNumber ? style.selectedPage : style.button}
>
{pageNumber}
</button>
))}
<button
className={style.button}
onClick={() => setPage(Math.min(numPages, page + pagesToShow))}
disabled={page >= numPages}
>
>
</button>
</nav>
);
}