Pagination vs Infinite Scroll

진성·2022년 4월 2일
0

리액트

목록 보기
8/19

Pagination

Pagination은 웹 사이트에서 데이터나 콘테츠를 여러 페이지를 분리하는 방법이다.
위와 같이 데이터나 콘텐츠를 여러 페이지로 나누어 보여주는 것이다.
코드로 보면 다음과 같다.

  const [startPage, setStartPage] = useState(1);
  const { data, refetch } = useQuery(FETCH_BOARDS);


  const onClickPage = (event: any) => {
    refetch({ page: Number(event.target.id) });
  };

 	return (
    <div>
    /////////////// 목록 데이터 /////////////////
        {new Array(10).fill(1).map((_, index) => // 새로운 배열
          index + startPage <= lastPage ? (
            <MyPage
              key={index + startPage}
              onClick={onClickPage}
              id={String(index + startPage)}
            >
              {index + startPage}
            </MyPage>
          ) : (
            <span></span>
          )
        )}
    </div>
 )

먼저 위에 보이는 목록 데이터를 불러왔다고 가정을 하고 보면, 일단 보여주고 싶은 페이지의 개수만큼 새로운 배열을 만들어 준 후에 배열 전체에 값을 주기 위해 map을 사용한다.
그리고 index + startPage를 보여준다. 이때 startPage 초깃값을 1로 줘야 한다.
그 이유는 index는 0부터 시작하기에 초깃값에 1을 줘서 0부터 데이터를 받아오지 않을 수 있다.
이제 클릭했을 때 이벤트를 주기 위해 onClick을 주고 refetch가 되는 함수를 실행해 준다.
refetch를 주지 않으면 page가 바뀌어도 렌더링 되지 않기 때문에 refetch를 해주어야 한다.

  const [startPage, setStartPage] = useState(1);
  const { data, refetch } = useQuery(FETCH_BOARDS);



  const onClickPage = (event: any) => {
    refetch({ page: Number(event.target.id) });
  };

  const onClickPrevPage = (event: any) => {
    setStartPage((prev) => prev - 10);
    refetch({ page: startPage - 10 });
  };

  const onClickNextPage = (event: any) => {
    setStartPage((prev) => prev + 10);
    refetch({ page: startPage + 10 });
  };
  
 	return (
    <div>
    /////////////// 목록 데이터 /////////////////
      <MyPage onClick={onClickPrevPage}>이전 페이지</MyPage>
        {new Array(10).fill(1).map((_, index) => // 새로운 배열
          index + startPage <= lastPage ? (
            <MyPage
              key={index + startPage}
              onClick={onClickPage}
              id={String(index + startPage)}
            >
              {index + startPage}
            </MyPage>
          ) : (
            <span></span>
          )
        )}
      <MyPage onClick={onClickNextPage}>다음 페이지</MyPage>
    </div>
 )

이제 다음 페이지로 넘어가기 위한 버튼과 이전 페이지로 넘어가기 위한 버튼을 만들어준다.
클릭했을 때 함수가 실행되면서 setStartPage에 값을 -10 과 +10을 이용해 업데이트를 해준다.
이때도 refetch를 같이 해줘야 하기 때문에 refetch 함수도 같이 실행될 수 있게 해준다.
하지만 이렇게만 해주면 문제가 생길 수 있다.
1페이지나 데이터가 있는 마지막 페이지 그 이상 넘어가게 된다.

  const [startPage, setStartPage] = useState(1);
  const { data, refetch } = useQuery(FETCH_BOARDS);
  const { data: dataBoardsCount } = useQuery(FETCH_BOARDS_COUNT);

  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 - 10 });
  };

  const onClickNextPage = (event: any) => {
    if (startPage + 10 >= lastPage) return;
    setStartPage((prev) => prev + 10);
    refetch({ page: startPage + 10 });
  };
  
 	return (
     /////////////// 목록 데이터 /////////////////
    <div>
      <MyPage onClick={onClickPrevPage}>이전 페이지</MyPage>
        {new Array(10).fill(1).map((_, index) => // 새로운 배열
          index + startPage <= lastPage ? (
            <MyPage
              key={index + startPage}
              onClick={onClickPage}
              id={String(index + startPage)}
            >
              {index + startPage}
            </MyPage>
          ) : (
            <span></span>
          )
        )}
      <MyPage onClick={onClickNextPage}>다음 페이지</MyPage>
    </div>
 )

이를 해결하기 위해 다음과 같이 조건을 걸어줘서 조건에 걸리면 바로 return 하게 돼서 setState에 값이 업데이트되지 않는다.
마지막 페이지의 조건 같은 경우는 페이지 데이터의 카운트를 불러와 나누기 원하는 페이지만큼 해준 후 숫자를 올림 해주는 Math.ceil 메서드를 사용해서 올림 한 페이지를 변수에 할당해 준다.
그리고 그 변수보다 크거나 같다면 함수가 바로 종료되게 하면 된다.
이때 또 주의해야 할 점으로 올림 한 숫자기 때문에 데이터가 없는 페이지까지 보여줄 경우가 있기 때문에 웹사이트에 렌더 해주는 맵을 사용하는 부분에 한 번 더 조건을 걸어 페이지에 수만큼 돌고 조건에 걸린다면 빈 곳을 보여주게 하면 된다.
이렇게 되면 위에 gif에 보이는 화면과 같이 잘 동작하는 것을 볼 수 있다

Infinite Scroll

Infinite Scroll은 사용자가 페이지 가장 아래에 도달할 때 데이터나 콘텐츠가 계속 로드가 되게 하는 방식이다.
이 방법은 페이스북, 인스타그램, 트위터 와 같은 소셜 미디어 웹사이트에서 이름을 알렸다.
위는 react-infinite-scroller(https://www.npmjs.com/package/react-infinite-scroller)라는 라이브러리를 사용하였다.
코드로 보면 다음과 같다.

import InfiniteScroll from "react-infinite-scroller";

const { data, fetchMore } = useQuery(FETCH_BOARDS);

  console.log(data);

  const onLoadMore = () => {
    if (!data) return;
    fetchMore({
      variables: { page: Math.ceil(data.fetchBoards.length / 10) + 1 },
      updateQuery: (prev, { fetchMoreResult }) => {
        if (!fetchMoreResult.fetchBoards)
          return {
            fetchBoards: [...prev.fetchBoards],
          };
        return {
          fetchBoards: [...prev.fetchBoards, ...fetchMoreResult.fetchBoards],
        };
      },
    });
  };

  return (
    <div style={{ height: "1500px", overflow: "auto" }}>
      <InfiniteScroll
        pageStart={0}
        loadMore={onLoadMore}
        hasMore={true}
        useWindow={false}
      >
        {data?.fetchBoards.map((el) => (
          <MyRow key={el._id}>
            <MyColumn>{el._id}</MyColumn>
            <MyColumn>{el.title}</MyColumn>
            <MyColumn>{el.writer}</MyColumn>
          </MyRow>
        )) || <div></div>}
      </InfiniteScroll>
    </div>
  );
};

먼저 라이브러리를 사용하기 위해서 npm에서 설치나 추가를 해줘야 한다.
그 후에 InfiniteScroll을 import 해준다.
그리고 그 사이에 보여줄 데이터 아이템을 넣어준다.
이제 동작하게 하기 위해 제공해 준 loadMore에 실행시킬 함수를 넣어준다.
함수 실행의 동작을 보면 먼저 fetchMore로 데이터를 불러온다.
variables에 들어오는 값으로는 데이터를 10으로 나눈 후에 올림 해준 숫자 더하기 1을 해준다.
이렇게 되면 데이터가 하나씩 추가될 수 있다.
updateQuery로 이전 데이터와 추가된 데이터를 불러온다.
이때 조건을 걸어 추가된 데이터가 없다면 이전 데이터를 바로 리턴해주는 조건을 걸어준다.
그 조건에 걸리지 않으면즉 추가된 데이터가 있다면 spread(전개 구문)을 이용해 이전 데이터와 추가 데이터를 추가해서 받아오게 된다.
이렇게 되면 위 gif 파일에 보이는 것과 같이 작동하게 된다.

전개 구문(spread)을 사용하면 배열이나 문자열과 같이 반복 가능한 문자를 0개 이상의 인수 (함수로 호출할 경우) 또는 요소 (배열 리터럴의 경우)로 확장하여, 0개 이상의 키-값의 쌍으로 객체로 확장시킬 수 있습니다. *mdn

profile
풀스택 진행중...

0개의 댓글