이번에 프로젝트에서 페이지네이션을 버튼을 구현해봤다.
다 구현해보고 나니 나름..? UI와 로직을 잘 분리한 것 같다는 생각이 들어서, 코드를 한 번 가지고 와봤다.
더보기
- Next JS app router
- tailwind
- typescript
[ 버튼 UI ] PagiNationButton
export default const PagiNationButton = ({
currentPage,
totalPage,
handleCurrentPage,
hiddenCount = false, // 두 번째 유형처럼 사용하기 위한 prop
}: PagiNationButtonProps) => {
return (
<div className='flex items-center pc:gap-4 mb:gap-2.5 '>
{!hiddenCount && (
<p className='text-sm text-tp-black_700'>
{totalPage} 페이지 중 {currentPage}
</p>
)}
<div className='flex justyfy-center items-center'>
<button
id='previous'
onClick={handleCurrentPage}
type='button'
className='border border-solid border-tp-gray_700 rounded-l-md active:bg-tp-gray_600 pc:p-3 mb:p-2.5'>
<div className='w-4 h-4 relative'>
<Image fill src={ArrowForwardIcon} alt='다음 페이지 보기' />
</div>
</button>
<button
id='next'
onClick={handleCurrentPage}
type='button'
className='border border-solid border-tp-gray_700 rounded-r-md active:bg-tp-gray_600 pc:p-3 mb:p-2.5'>
<div className='w-4 h-4 relative'>
<Image fill src={ArrowBackwardIcon} alt='다음 페이지 보기' />
</div>
</button>
</div>
</div>
);
};
프롭으로 사용할 데이터의 totalCount와 currentCount는 사용하는 컴포넌트에서 데이터 리퀘스트를 받아 띄워줄 것이고, 누르는 버튼의 id에 따라서 currentCount를 더하고 빼는 이벤트 핸들러를 전달해줄 것이다.
이때 쿼리로 전달해줘야하는 정보는 몇 개씩 보여줄 것인지와 현재 페이지가 몇 페이지인지이다.
나는 사용하는 곳에서 매번 이벤트 핸들러를 정의해서 내려주기보다, 페이지네이션을 사용하는 곳이 여러 곳이기 때문에 커스텀 훅으로 빼서 사용하기로 했다.
[ 로직 분리 ] usePagiNation
각 각의 버튼에 다른 함수를 지정해서 사용해줘도 되지만, 나는 하나의 함수 안에서 버튼의 id에 따라 값이 더해지고 빼지도록 했다.
export const usePagiNation = () => {
const [pagiNation, setPagiNation] = useState({
currentPage: 1,
totalPage: 1,
});
const handleCurrentPage = (event: MouseEvent<HTMLButtonElement>) => {
// 버튼의 id가 next인지 아닌지에 따라서 다른 함수가 실행되도록 했다.
if (event.currentTarget.id === 'next') {
if (pagiNation.currentPage < pagiNation.totalPage) {
setPagiNation(prevState => ({
...prevState,
currentPage: pagiNation.currentPage++,
}));
}
} else {
if (pagiNation.currentPage > 1) {
setPagiNation(prevState => ({
...prevState,
currentPage: pagiNation.currentPage--,
}));
}
}
};
return { pagiNation, setPagiNation, handleCurrentPage };
};
이렇게 분리했다면, 이제는 실제로 사용해 볼 시간이다.
구성원 테이블에서 페이지네이션을 적용해보자.
// 페이지네이션과 무관한 로직은 제거했다.
const MemberTable = ({ dashboardId }: { dashboardId: number }) => {
const { pagiNation, setPagiNation, handleCurrentPage } = usePagiNation();
const showCount = 5;
export default const handleLoadMembers = async ({dashboardId}:{dashboardId : number}) => {
// totalCount를 가져와서, api 함수에 알맞은 형태로 전달해주자.
try {
const { members, totalCount } = await getDashBoardMembers({
currentPage: pagiNation.currentPage,
showCount: showCount,
dashboardId: dashboardId,
});
// api 함수를 통해 받아온 totalCount로 총 몇 페이지인지 계산해서 state를 업데이트 해줬다.
setPagNation(prevState => ({
...prevState,
totalPage: Math.ceil(totalCount / showCount),
}));
setMembers(members);
} catch (error: any) {
alert(error);
}
};
// useEffect를 통해서 현재 페이지가 업데이트 될 때마다 데이터를 재렌더링 되도록 해주었다.
useEffect(() => {
handleLoadMembers();
}, [pagiNation.currentPage]);
return (
<TableLayout
title='구성원'
headerContent={
<PagiNationButton
totalPage={pagiNation.totalPage}
currentPage={pagiNation.currentPage}
handleCurrentPage={handleCurrentPage}
/>
}
tableContent={MemberList}
/>
);
};
페이지네이션이 잘 동작한다 !!
'💡뚝딱뚝딱 만들어보자 ~! :) > Taskify' 카테고리의 다른 글
[input type="file"] 내가 원하는 모양으로 바꾸기 (0) | 2024.04.18 |
---|