TIL 20220127 페이지네이션 구현하기 (+ 무한스크롤)
페이지네이션
여러 콘텐츠를 페이지들로 분리하고, 페이지 하단에 있는 숫자 형식의 링크를 클릭하여 다른 콘텐츠로 이동하도록 하는 UI를 페이지네이션이라고 한다.
이런 페이지네이션을 구현하기 위하여 어떤 기능들을 구현해야 할까?
나열된 숫자를 클릭하여 해당 페이지로 이동시키고, 이전페이지 혹은 다음페이지 버튼을 클릭하여 현재 화면에 나열된 숫자의 이전・이후 페이지들을 새로 나열해야 할 것이다.
이 글은 무지렁이 수준의 학습자가 복습을 위하여 작성한 글이므로, 정-말 맨 처음부터 차근차근히 살펴보도록 하겠다.
우선, 숫자들을 나열해보자.
<span onClick={onClickPage} id="1"> 1 </span>
<span onClick={onClickPage} id="2"> 2 </span>
<span onClick={onClickPage} id="3"> 3 </span>
...........
각 숫자를 누를때마다 id값의 페이지로 이동하는 onClickPage 함수가 실행될 것이다. 그런데 이렇게 노가다로 쓰면 비효율적이므로 map을 이용하여 뿌려보자.
{new Array(10).fill(1).map((_, index) => (` ${index + 1} `))}
이러면 1부터 10까지 나열된다. 우리는 숫자만 나열하고 끝이 아니므로
온클릭 이벤트 핸들러 함수와 연결하고 아이디값도 함께 줘보자.
{new Array(10).fill(1).map((_, index) => (
<span
key={index + 1}
onClick={onClickPage}
id={String(index + 1)}
>
{` ${index + 1} `}
</span>
))}
이제 1부터 10까지의 숫자를 누르면 각 페이지로 이동한다.
그런데 페이지가 1부터 10까지만 있는 것이 아니고, 20,30,40,... 페이지까지 더 있을 수 있다.
위의 키값과 아이디값 등에 있는 index+1에 1대신 11,21,31,... 이 들어가면 11,12,13,... 21,22,23,... 31,32,33,... 41,42,43,... 페이지도 뿌릴 수 있을 것이다.
useState를 이용하여 startPage값을 변동시키자.
컴포넌트 내부에서 바뀔수 있는 값을 설정할 때는 state를 이용하면 된다.
이 글은 함수 컴포넌트를 사용하는 전제하에 쓰여졌으므로, Hooks를 이용하여 state값을 저장하고, 이전페이지・다음페이지 버튼을 누를 시 state값을 10씩 감소 혹은 증가시킨 뒤, 위에서 뿌린 숫자들의 값도 바뀌게 해보자.
const [startPage, setStartPage] = useState(1);
startPage를 설정하고 초깃값을 1로 주었으니 이제 위의 index+1을 몽땅 index+startPage로 바꾸자.
{new Array(10).fill(1).map(
<span
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{` ${index + startPage} `}
</span>
)}
이전・다음페이지 버튼을 누를 시 startPage값이 10씩 변동되는 함수를 만들어보자.
const onClickPrevPage = () => {
if (startPage === 1) return; // ⭐️ 포인트 1
setStartPage((prev) => prev - 10); // ⭐️ 포인트 2
refetch({ page: startPage - 10 }); // ⭐️ 포인트 3
};
const onClickNextPage = () => {
if (startPage + 10 > lastPage) return; //⭐️ 포인트 4
setStartPage((prev) => prev + 10);
refetch({ page: startPage + 10 });
};
한 줄 한 줄 살펴보자.
없는 페이지 나열하지 않기
먼저 ⭐️포인트1과 ⭐️포인트4를 통하여 시작페이지가 1일 경우 startPage가 10이 감소되지 않도록 하고, 마지막 페이지가 이후에 10개의 페이지를 더이상 나열하지 않도록 함수를 return 시켰다.
setState의 비동기적 속성
⭐️포인트2에서 prev를 이용한 이유는 무엇일까? setState는 비동기적으로 작동한다. state가 바뀌면 해당 state를 사용하는 컴포넌트와 그 하위 자식 컴포넌트들이 다시 렌더링 되고, 다시 렌더링 된 후에야 state가 바뀐 것을 확인할 수 있다.
이전・다음 페이지의 첫번째 페이지를 새로 띄워주기
⭐️포인트3 Refetch
특정 유저 액션이 발생하면 쿼리 결과를 갱신하도록 해주는 방식이다. refetch 함수에게 새로 variables 오브젝트를 넘겨주려면 위의 예시코드와 같이 refetch( ) 소괄호 안 {} 중괄호 부분에 variables를 입력하면 된다. refetch를 사용하기 위해서는 useQuery 받아올 때 data말고도 refetch도 함께 입력하면 된다.
const { data, refetch } = useQuery(FETCH_BOARDS, { variables: { page: 1 } });
거의 다왔다. 이제 이전・다음 페이지 버튼과 연결만 하면 된다.
<span onClick={onClickPrevPage}>이전페이지</span>
~~~ 아까 작성한 map부분 코드 ~~~
<span onClick={onClickNextPage}>다음페이지</span>
추가적으로 고려할 부분
마지막 페이지 이후에도 표시되는 페이지를 숨기기
다양한 방식이 있겠지만 가장 간단한 방식은 조건부렌더링을 활용하는 것이다. 조건부렌더링에 관하여는 지난 포스팅에서 한번 설명하였는데, 여기서는 && 연산자를 이용한 방식을 사용하였다. &&앞의 값이 참이면 && 뒤를 렌더링하고, 거짓이면 앞을 렌더링한다.
{new Array(10).fill(1).map(
(_, index) =>
startPage + index <= props.lastPage && (
<span
key={index + startPage}
onClick={onClickPage}
id={String(index + startPage)}
>
{` ${index + startPage} `}
</span>
)
)}
현재 페이지넘버(startPage+index)가 마지막페이지보다 작거나 같으면 페이지 숫자를 표시하고, 거짓인 경우에는 아무것도 띄우지 않게 하였다.
Props로 CSS적 요소 넘겨주기
클릭한 페이지에 색상 속성을 줄 수 있다. 사용자가 클릭한 페이지를 받아오기 위해서 먼저 state를 선언하고, 온클릭 함수 실행시에 event.target.id를 이용하여 이용자가 클릭한 페이지의 값을 setState에 넣어주자.
const [activedPage, setActivedPage] = useState(1);
function onClickPage(event) {
const activedPage = Number(event.target.id);
setActivedPage(activedPage);//⭐️
refetch({ page: activedPage });
}
클릭한 페이지의 id가 현재 페이지와 동일한지 여부를 isActive속성에 반영시킨다.
{new Array(10).fill(1).map(
(_, index) =>
startPage + index <= lastPage && (
<Page
key={startPage + index}
onClick={onClickPage}
id={String(startPage + index)}
isActive={startPage + index === activedPage}
>
{startPage + index}
</Page>
)
)}
이제 css 스타일 속성을 주면 된다.
export const Page = styled.span`
margin: 0px 10px;
font-weight: ${(props) => (props.isActive ? "bold" : "normal")};
color: ${(props) => (props.isActive ? "blue" : "gray")};
무한스크롤
사용자가 페이지 하단에 도달했을 때 다음 페이지를 추가적으로 로드시키는 방식이다. 무한스크롤을 구현하는 방법은 여러 가지가 있을 수 있는데, 크게 3가지의 방식이 많이 사용되는 듯하다.
- 라이브러리 : react-infinite-scroller 등.....
https://www.npmjs.com/package/react-infinite-scroller - Scroll 이벤트
- Intersection Observer API
(참고)https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API
참고하면 좋을 유튜브 영상을 발견하여 공부하고자 첨부해본다.
라이브러리 없이 스크롤이벤트와 intersection observer api 두 가지 방법을 이용하여 무한스크롤을 구현하는 영상이다.
나중에 꼭 구현해서 따로 포스팅해야지...!!!!.....
Author And Source
이 문제에 관하여(TIL 20220127 페이지네이션 구현하기 (+ 무한스크롤)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@minimin123/TIL-20210127-페이지네이션저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)