페이지네이션은 게시글 목록 페이지에서 가장 흔하게 볼 수 있는 페이지 처리 방식으로 사용자가 페이지 하단에 있는 숫자 형식의 링크를 클릭하면 해당 페이지가 보여지게 하는 방식이다.
import { useQuery, gql } from "@apollo/client";
import styled from "@emotion/styled";
const FETCH_BOARDS = gql`
query fetchBoards($page: Int) {
fetchBoards(page: $page) {
_id
writer
title
contents
}
}
`;
const MyRow = styled.div`
display: flex;
`;
const MyColumn = styled.div`
width: 25%;
`;
export default function MapBoardPage() {
const { data, refetch } = useQuery(FETCH_BOARDS);
const onClickPage = (event: any) => {
// 클릭한 페이지를 FETCH_BOARD로 다시 불러와서 화면에 보여줌
refetch({ page: Number(event.target.id) });
};
return (
<div>
{data?.fetchBoards.map((el: any) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
{/* 사용하지 않는 값은 _로 표시해준다. */}
{new Array(10).fill(1).map((_, index) => (
<span key={index + 1} id={String(index + 1)} onClick={onClickPage}>
{index + 1}
</span>
))}
</div>
);
}
map을 이용해 (게시글)목록과 선택할 페이지 목록을 화면에 그려준다. 페이지를 선택하면 onClick 함수를 이용해 해당 페이지 번호를 event.target.id 를 이용해 변수에 담아 refetch에 필요한 page 정보로 넘겨준다. refetch 함수는 넘겨받은 페이지에 맞는 목록을 다시 불러와 화면에 보여준다.
graphQL의 useQuery에서 제공하는 refetch를 사용하기 위해 data 와 함께 refetch 함수를 불러와야 한다.
// 시작 페이지 (1,11,21,31 ...)
const [startPage, setStartPage] = useState(1);
//이전 페이지 10개를 보여주는 함수
const onClickPrevPage = () => {
setStartPage((prev) => prev - 10);
refetch({ page: startPage - 10 });
};
//이후 페이지 10개를 보여주는 함수
const onClickNextPage = () => {
setStartPage((prev) => prev + 10);
refetch({ page: startPage + 10 });
};
return (
<div>
{data?.fetchBoards.map((el: any) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
<span onClick={onClickPrevPage}>{"<"}</span>
{/* 사용하지 않는 값은 _로 표시해준다. */}
{new Array(10).fill(1).map((_, index) => (
<span
key={index + startPage}
id={String(index + startPage)}
onClick={onClickPage}
>
{" "}
{index + startPage}{" "}
</span>
))}
<span onClick={onClickNextPage}>{">"}</span>
시작 페이지를 선언해준다. 페이지의 시작은 항상 1로 끝난다. 1,11,21,31 ...
현재 보여지는 페이지가 21-30페이지인 경우 onClickPrevPage 함수가 실행되면 11-20페이지가 보여지고 onClickNextPage 함수가 실행되면 31-40페이지게 보여지게 되는 것이다.
//마지막 페이지 수를 알아야 한다.(쿼리 생략)
const { data: dataBoardsCount } = useQuery(FETCH_BOARD_COUNT);
const lastPage = Math.ceil(dataBoardsCount?.fetchBoardsCount / 10);
한 페이지에 게시글이 10개라면 전체 게시글 수를 10으로 나누어 올림 해준 값이 전체 페이지 수가 된다.
const onClickPrevPage = () => {
if (startPage === 1) return;
setStartPage((prev) => prev - 10);
refetch({ page: startPage - 10 });
};
const onClickNextPage = () => {
if (startPage + 10 <= lastPage) {
setStartPage((prev) => prev + 10);
refetch({ page: startPage + 10 });
}
};
return (
<div>
{data?.fetchBoards.map((el: any) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
<span onClick={onClickPrevPage}>{"이전페이지"}</span>
{/* 사용하지 않는 값은 _로 표시해준다. */}
{new Array(10).fill(1).map((_, index) => {
return (
index + startPage <= lastPage && (
<span
key={index + startPage}
id={String(index + startPage)}
onClick={onClickPage}
>
{" "}
{index + startPage}{" "}
</span>
)
);
})}
<span onClick={onClickNextPage}>{"다음 페이지"}</span>
</div>
);
}
startPage가 1인 경우 이전 페이지를 불러오지 않도록 if 문을 이용해 막아주고, 조건부 렌더링을 이용해 마지막 페이제까지만 페이지 수가 나타나도록 코드를 작성한다.
무한 스크롤은 인스타 그램과 같이 사용자가 페이지 하단에 도달했을 때, 콘텐츠가 계속 로드되어 화면에 계속 보여지는 방식이다.
무한 스크롤의 경우 라이브러리를 사용해 쉽게 구현할 수 있다. 무한 스크롤 라이브러리를 설치하고 import 한다.
<InfiniteScroll
pageStart={0}
loadMore={loadFunc}
hasMore={true || false}
loader={<div className="loader" key={0}>Loading ...</div>}>
{items} // <-- This is the content you want to load
</InfiniteScroll>
무한 스크롤을 걸어주고 싶은 아이템을 InfiniteScroll 태그를 이용해 감싸주면 된다.
페이지네이션의 경우 특정한 주제로 묶여서 보여지는 경우(ex Q&A 게시판)에 적합하다. 무한 스크롤의 경우 특정된 주제나 목적 없이 계속해서 화면에 보여지는 경우(ex 인스타그램, 페이스북)에 더 적합하다. 따라서 페이지네이션과 무한스크롤의 경우에는 목적에 따라 맞게 사용해야한다.
개인적인 생각으로 무한 스크롤의 경우 라이브러리를 사용하기 때문에 페이지네이션보다 구현하는 것에서는 더 쉽다고 생각한다.
참고 영상 자료 출처 - 오늘의 집 https://ohou.se/projects?writer=self