UX - pagination vs infinite scroll

ryh0629·2022년 5월 29일
0

Pagination-페이지네이션

페이지네이션은 게시글 목록 페이지에서 가장 흔하게 볼 수 있는 페이지 처리 방식으로 사용자가 페이지 하단에 있는 숫자 형식의 링크를 클릭하면 해당 페이지가 보여지게 하는 방식이다.

pagenation 구현

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-10까지의 10개의 페이지만 불러올 수 있도록 구현되어 있다. 따라서 더 많은 페이지를 보여주기 위해서 몇 가지 단계가 더 필요하다.

// 시작 페이지 (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 문을 이용해 막아주고, 조건부 렌더링을 이용해 마지막 페이제까지만 페이지 수가 나타나도록 코드를 작성한다.

Infinite scroll-무한 스크롤


무한 스크롤은 인스타 그램과 같이 사용자가 페이지 하단에 도달했을 때, 콘텐츠가 계속 로드되어 화면에 계속 보여지는 방식이다.

무한 스크롤 구현

https://www.npmjs.com/package/react-infinite-scroller

무한 스크롤의 경우 라이브러리를 사용해 쉽게 구현할 수 있다. 무한 스크롤 라이브러리를 설치하고 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 태그를 이용해 감싸주면 된다.

pagination vs infinite scroll

페이지네이션의 경우 특정한 주제로 묶여서 보여지는 경우(ex Q&A 게시판)에 적합하다. 무한 스크롤의 경우 특정된 주제나 목적 없이 계속해서 화면에 보여지는 경우(ex 인스타그램, 페이스북)에 더 적합하다. 따라서 페이지네이션과 무한스크롤의 경우에는 목적에 따라 맞게 사용해야한다.

개인적인 생각으로 무한 스크롤의 경우 라이브러리를 사용하기 때문에 페이지네이션보다 구현하는 것에서는 더 쉽다고 생각한다.

참고 영상 자료 출처 - 오늘의 집 https://ohou.se/projects?writer=self

profile
developer

0개의 댓글