🙌구현 목표 : 페이지네이션 구현하기
다음과 같은 페이지 네이션을 구현하여야 한다.
즉, 1~10까지 페이지 가 보여지고
페이지 단위는 10씩 넘겨진다.
◀ 클릭 시 이전 페이지 => 현재 페이지가 11~20일 경우 => 1페이지로 이동
▶ 클릭 시 다음 페이지로 넘어간다. => 현재 페이지가 11~20일 경우 => 21페이지로 이동
First는 첫 페이지로
Last는 마지막 페이지로 이동한다.
1. Pagenation 컴포넌트에 maxPage(최대 페이지), currentPage(현재 페이지), setCurrentPage, visiblePageCount(페이지 단위)를 넘겨준다.
export const HomePage = () => {
const [pagenation, setPagenation] = useState(1);
return (
// Pagenation
<Pagenation
maxPage={49}
currentPage={pagenation}
setCurrentPage={setPagenation}
visiblePageCount={10}
/>
);
};
2. 넘겨받은 인자를 통해 첫 페이지 목록부터 생성한다.
export const Pagenation: React.FC<IPagenationProps> = ({
maxPage,
currentPage,
setCurrentPage,
visiblePageCount,
}) => {
const currentPageBase = Math.floor(currentPage / visiblePageCount) * 10;
const pageList = useMemo(() => {
//첫 페이지
if (1 === currentPage || 1 > currentPage) {
return Array.from({ length: visiblePageCount }, (_, index) => index + 1);
}
}, [currentPage]);
여기까지를 풀이하자면,
- Array.from({객체}) : 어떤 객체를 얕은 복사하여 새로운 배열로 생성한다. => visiblePageCount(페이지 단위)만큼 배열을 생성한다. =>Array.map()과 같은 기능을 한다.
- { length : visiblePageCount } => visiblePageCount 만큼 유사 배열 객체를 생성한다.
=> 예를들어 { length : x } 만 정해줄 경우 이렇게 생성된다.
{
0 : undefined,
1 : undefined,
2 : undefined,
3 : undefined,
4 : undefined,
}
- Array.from( { length : visiblePageCount })
=> 유사 배열 객체를 얕게 복사하여 새로운 배열을 생성한다. 결과는 다음과 같다.
[
0 : undefined,
1 : undefined,
2 : undefined,
3 : undefined,
4 : undefined,
]
즉 이에 대입해 보면
const pageList = useMemo(() => {
//첫 페이지
if (1 === currentPage || 1 > currentPage) {
return Array.from({ length: visiblePageCount }, (_, index) => index + 1);
}
}, [currentPage]);
- Array.from({ length: visiblePageCount }, (_, index) => index + 1);
=> length가 visiblePageCount(페이지 단위:10)만큼인 첫 페이지 배열이 생성된다. (1~10까지)
(_, index) => 여기서 매개변수인 value와 index를 설정 가능한데, 배열은 0부터 시작하기 때문에 페이지 번호가 0,1,2,3 ... 이 아니라 1,2,3... 으로 설정되도록 값을 index + 1 로 설정한다.
이를 리턴하는 pageList를 맵핑하여 새로운 배열로 생성해 보면, 첫 페이지의 배열이 생성된 것을 확인할 수 있다.
<ul className={styles.flex}>
{pageList.map((item) => {
return (
<li
key={item}
onClick={() => setCurrentPage(item)}
className={currentPage === item ? styles.accord : styles.disaccord}>
{item}
</li>
);
})}
</ul>
3. 첫 페이지를 제외한 그 외 페이지 목록을 설정한다.
const currentPageBase = Math.floor(currentPage / visiblePageCount) * 10;
const pageList = useMemo(() => {
//첫 페이지
if (1 === currentPage || 1 > currentPage) {
return Array.from({ length: visiblePageCount }, (_, index) => index + 1);
}
//그 외 페이지
return Array.from({ length: visiblePageCount }, (_, index) => currentPageBase + index + 1);
}, [currentPage]);
그 외의 페이지 목록들은 기본적으로
11 ~ 20
21 ~ 30
31 ~ 40 ... 과 같이 10단위들로 생성되어야 한다.
- 먼저 페이지 목록 배열을 생성하기 위해 currentPageBase를 설정하였다.
const currentPageBase = Math.floor(currentPage / visiblePageCount) * 10;
만약 currentPage(현재 페이지)가 21이라면,
21을 visiblePageCount(페이지 단위)인 10으로 나누고 나머지 부분은 Math.floor로 내림 처리한다.
그럼 2가 반환되는데, 이 2에 10을 곱하여 currentPageBase 20을 만든다.
=> (21/10) = 2.1 => 내림처리 => 2 => 2* 10(페이지 단위) => 20
- 생성한 currentPageBase에 나머지 index+1 들을 더하여 21, 22, 23 ... 등과 같은 페이지 배열을 생성한다.
return Array.from({ length: visiblePageCount }, (_, index) => currentPageBase + index + 1);
다음과 같이 페이지가 넘어가면 10단위씩 생성되는 것을 확인할 수 있다.
❗그런데 여기서 문제가 생겼다. 현재 페이지가 10페이지인데 11~20페이지 목록이 반환된다..
1~10까지 페이지 목록에서
1~9까지의 내림처리는 1/10 => 0.1 => 0으로 반환되지만
10일 경우 10/10 => 1 => 1으로 반환되어 버린다...
결과적으로 currentPage가 10,20,30 ... 이렇게 떨어질 경우 베이스가 1~9까지와 달리 한단계 높게 측정되어,
현재 페이지가 10페이지일 경우 1~10목록이 보여져야 하는데, 11~10를 반환하는 문제가 발생하였다.
✅ 위 문제를 다음과 같이 해결해 보았다.
- beforePageBase를 만들어 10,20,30과 같이 그전 값과 한단계 높게 측정된 값을 다시 -1하여 내려준 후 다른 1~9값들과 같은 0으로 반환하게 하여
const beforePageBase = Math.floor(currentPage / visiblePageCount - 1) * 10;
만약 현재 페이지가 10페이지여도 동일하게 1~10페이지가 보여지게 만들었다.
const pageList = useMemo(() => {
if (1 === currentPage || 1 > currentPage) {
return Array.from({ length: visiblePageCount }, (_, index) => index + 1);
}
// 10, 20, 30 등 나머지가 남지않는 수일 경우 값을 -1하여 다른 페이지목록과 같이 보여지도록 함
if (0 === currentPage % visiblePageCount) {
return Array.from({ length: visiblePageCount }, (_, index) => beforePageBase + index + 1);
}
✨현재 페이지가 10페이지, 20페이지, 30페이지 등 일 때에도 다른 페이지목록들과 같은 페이지목록을 생성한다.
4. First , Last 버튼 기능 넣기
- 이제 First 버튼을 클릭하면 맨 처음 페이지(1페이지)로 이동하고, Last 버튼(49페이지)을 클릭하면 맨 마지막 페이지로 이동하는 기능을 넣어보려고 한다.
currentPage로 상태값을 변경해 주면, 너무나 쉽게 구현이 가능하다.
//First
<button className={styles.button} onClick={() => setCurrentPage(1)}>
First
</button>
//Last
<button className={styles.button} onClick={() => setCurrentPage(maxPage)}>
Last
</button>
5. ◀ , ▶ 버튼 기능 넣기
- ▶ 버튼 : 이전 페이지 목록으로 이동 => 현재 21~30페이지 일 경우, 버튼 클릭 시 11페이지로 이동
=> 위에서 이미 만들어 놓음 NextPageBase를 사용하면 어렵지않게 구현 가능하다.
=> 이 때 현재 페이지가 1페이지 보다 작아질 경우 페이지가 음수로 무한히 생성 되는 것을 방지하기 위해 조건을 걸어준다.
<button
className={styles.button}
onClick={() => {
setCurrentPage((prev) => {
if (1 < prev) { //현재 페이지가 1페이지 보다 작아질 경우 페이지가 음수로 무한히 생성 되는 것을 방지
return beforePageBase + 1;
}
return prev; //반드시 예외처리
});
}}>
◀
</button>
- ◀ 버튼 : 이전 페이지 목록으로 이동 => 현재 21~30페이지 일 경우, 버튼 클릭 시 11페이지로 이동
=> 위에서 이미 만들어 놓음 BeforePageBase를 사용하면 어렵지않게 구현 가능하다.
=> 이 때 현재 페이지가 maxPage 보다 커질 경우 페이지가 무한히 생성 되는 것을 방지하기 위해 조건을 걸어준다.
=> 설정한 조건 외 예외처리를 반드시 해야 한다. (❗jsx에서 if문을 사용할 수 있는지에 대해 다시 한번 확인이 필요하다.)
<button
className={styles.button}
onClick={() =>
setCurrentPage((prev) => {
if (maxPage > prev) {
return nextPageBase + 1;
}
return prev;
})
}>
▶
</button>
6. 마지막 페이지 설정
이와 같이 조금 어려웠지만... 다행히 정상적으로 목표했던 모든 기능이 작동하는 페이지네이션을 구현할 수 있어 뿌듯했다.😆
'Project > 향수프로젝트' 카테고리의 다른 글
[React] 페이지네이션(Pagenation) 구현하기 - 코드리뷰와 리팩토링 (0) | 2022.12.28 |
---|