antDesign의 pagination
https://ant.design/components/pagination/#header
npm의 infinite Scroll
https://www.npmjs.com/package/react-infinite-scroller
대부분의 사이트들을 보면 목록이 있고 그 목록들을 넘겨주는 페이지 버튼이 있다.
이 버튼들에 담겨있는 기능을 Pagination 이라 부르며 거의 모든 사이트 들에서 사용되고 있는 기능이다.
라이브러리를 사용하면 편하지만 직접 코드를 작성해보았다.
==import와 gql, style 부분은 전부 다르니 생략==
-------------------------------------------------------------------
export default function PaginationPage() {
// useQuery를 통해 데이터를 받아왔고 이를 data에 할당해준부분
const { data, refetch } = useQuery(FETCH_BOARDS);
const [startPage, setStartPage] = useState(1);
// useQuery를 통해 데이터를 받아왔고 이를 dataBoardsCount에 할당해준부분
const { data: dataBoardsCount } = useQuery(FETCH_BOARDS_COUNT);
// 페이지를 넘길 기준점 부분이다 Math.ceil 수학함수를 사용한 모습이다.
const lastPage = Math.ceil(dataBoardsCount?.fetchBoardsCount / 10);
// 페이지를 누르는 부분
const onClickPage = (event: any) => {
refetch({ page: Number(event.target.id) });
};
//이전 페이지 버튼
const onClickPrevPage = (event: any) => {
if (startPage === 1) return;
setStartPage((prev) => prev - 10);
refetch({ page: startPage - 1 });
};
//다음 페이지 버튼
const onClickNextPage = (event: any) => {
if (startPage + 10 > lastPage) return;
setStartPage((prev) => prev + 10);
refetch({ page: startPage + 10 });
};
//반환되어 실제로 보여지는 부분
return (
<div>
// 이 부분은 query로 넘겨받은 data에 담겨있는 배열의 객체와 그 요소들을 map을 통해 표시한 부분이다.
// 주제인 Pagination과는 상관없는 부분이다.
{data?.fetchBoards.map((el: any) => (
<MyRow key={el._id}>
<MyColumn>
<input type="checkbox" />
</MyColumn>
{/* <MyColumn>{el._id}</MyColumn> */}
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
<span onClick={onClickPrevPage}>이전페이지</span>
//실제 기능이 작동하는 페이지 부분
{/* 사용하지 않는 요소는 _, 처리해준다. */}
{new Array(10).fill(1).map((_, index) =>
index + startPage <= lastPage ? (
<button
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{``}
{index + startPage}
</button>
) : (
<span></span>
)
)}
<span onClick={onClickNextPage}>다음페이지</span>
</div>
);
}
길게 올렸지만 사실 핵심은
{new Array(10).fill(1).map((_, index) =>
index + startPage <= lastPage ? (
<button
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{``}
{index + startPage}
</button>
) : (
<span></span>
)
)}
이 부분이 전부이다. new Array를 통해 새로운 배열을 만들어 map을 사용하였으며
index + startPage <= lastPage
를 조건으로 제시해
삼항연산자를 사용하여
버튼을 띄우거나 빈공간 표시해준다.
이렇게 되면 마지막 게시글이 15번페이지에 있다면
다음 글목록으로 넘길경우 16~20 페이지는 <span></span>
이 전부이며 화면상에는 나오지않게된다.
infinite Scrolld은 npn의 Library를 사용하였다.
export default function StaticRoutedPage() {
const { data, fetchMore } = useQuery(FETCH_BOARDS);
console.log(data);
const onLoadMore = () => {
if (!data) return; // 데이터가 없으면 요청하지말하라
fetchMore({
variables: { page: Math.ceil(data?.fetchBoards.length / 10) },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult.fetchBoards)
return { fetchBoards: [...prev.fetchBoards] };
return {
fetchBoards: [...prev.fetchBoards, ...fetchMoreResult.fetchBoards],
};
},
});
};
return (
<div style={{ height: "700px", overflow: "auto" }}>
<InfiniteScroll
pageStart={0}
loadMore={onLoadMore}
// loadMore={loadFunc} //추가로 패치할것
hasMore={true}
// hasMore={true || false}
// loader={
// <div className="loader" key={0}>
// Loading ...
// </div>
// }
useWindow={false}
>
{data?.fetchBoards.map((el, index) => (
<MyRow key={el._id}>
<MyColumn>{el._id}</MyColumn>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
</InfiniteScroll>
</div>
);
핵심이 되는 부분은
return문 안쪽의 <div>
태그 부터 그 사이의 부분이다.
<div style={{ height: "700px", overflow: "auto" }}>
<InfiniteScroll
pageStart={0}
loadMore={onLoadMore}
// loadMore={loadFunc} //추가로 패치할것
hasMore={true}
// hasMore={true || false}
// loader={
// <div className="loader" key={0}>
// Loading ...
// </div>
// }
useWindow={false}
>
{data?.fetchBoards.map((el, index) => (
<MyRow key={el._id}>
<MyColumn>{el._id}</MyColumn>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
</InfiniteScroll>
</div>
위에선 저렇게 코드를 작성했지만 실제로는
<InfiniteScroll
pageStart={0}
loadMore={loadFunc}
hasMore={true || false}
loader={
<div className="loader" key={0}>
Loading ...
</div>
}
>
{data}
</InfiniteScroll>
같은형식으로 되어있다.
pageStart={0}
는 시작할 페이지의 인덱스를 나타내며
loadMore={loadFunc}
은 이후 실행될함수를 나타내고
hasMore={true || false}
은 스크롤에 더 가져올 정보가 있는지를 boolean 값으로 나타낸다.
loader={~}
부분은 로딩을 보여주는게 전부니 따로 설명을 생략하겠다.
<div style={{ height: "700px", overflow: "auto" }}>
는 직접적인 범위를 나타내주며
useWindow={false}
는 스크롤을 해당 윈도우 페이지가 아닌 독립적인 스크롤을 사용하겠다 한것이다.
아래부분은 loadMore={loadFunc}
에 {loadFunc}
대신 들어갈 함수부분인 {onLoadMore}
이다.
const onLoadMore = () => {
if (!data) return; // 데이터가 없으면 요청하지말하라
fetchMore({
variables: { page: Math.ceil(data?.fetchBoards.length / 10) },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult.fetchBoards)
return { fetchBoards: [...prev.fetchBoards] };
return {
fetchBoards: [...prev.fetchBoards, ...fetchMoreResult.fetchBoards],
};
},
});
};
fetchMore({~
부분이 실제로 추가 정보를 가져올 정보이며
variables
는 gql 쿼리 부분을 통해서 가져와야 할 기본적인 정보들이고
updateQuery
는 return
전 업데이트할 정보들 이다.
(prev, { fetchMoreResult })
라는 부분이 있는데 prev
는 이전의 정보들을 뜻하며
{ fetchMoreResult }
는 더 가져올 정보들의 결과값을 나타낸다.
fetchMore
의 선언은 const { data, fetchMore } = useQuery(FETCH_BOARDS);
에서 useQuery
를 통해 데이터와 함깨 선언하였으며
즉 { fetchMoreResult }
는 FETCH_BOARDS
라는 gql의 정보들의 결과인 셈이다.
마지막 return
은 최종적으로 반환될 정보 이며
fetchBoards: [...prev.fetchBoards, ...fetchMoreResult.fetchBoards],
[...prev.~~, ...fetchMoreResult.~~]
는 기존값들과 추가 값들을 합쳐
fetchBoards
에 담아 반환함을 의미한다.