안녕하세요

[UX] Channels 페이지네이션 적용 본문

유튜브컨텐츠탐색-StelLife

[UX] Channels 페이지네이션 적용

sakuraop 2023. 8. 16. 03:41

적용 필요성: 등록된 채널이 많아짐에 따라 페이지 로드 비용이 커짐

초기에는 100~150개 가량의 채널이 등록되어 있었다.

 

지속적으로 활동을 하지 않거나 연관 없는 채널을 제외 했음에도

현재는 지속적으로 관련 채널이 늘어남에 따라서 350~450개 가량의 채널이 등록되어 있다.

 

한 번에 모든 데이터를 불러오고 렌더링 하기에는 너무 많기에

페이지네이션과 무한스크롤 중에서 고민하다가 페이지네이션을 택했다.

 

채널을 둘러보고 싶다면 1~2페이지의 연관성이 높은 채널과,

마지막 페이지엔 어떤 채널이 있는지를 주로 확인하기 때문이다.


exports.getSortedChannelsData = async (req, res) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const pageSize = parseInt(req.query.pageSize) || 30;

    const sorted_channels = await db.collection("sorted_channels");
    const channelCount = await sorted_channels.countDocuments();

    const sortedChannelList = await sorted_channels
      .find({})
      .skip((page - 1) * pageSize)
      .limit(pageSize)
      .toArray();

    res.status(200).json({ channels: sortedChannelList, channelCount });
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Internal server error" });
  }
};


page, pageSize 불러올 페이지와, 페이지 크기를 쿼리로 요청한다.

channelCount 최대 페이지를 설정하기 위해서 전체 채널의 갯수를 가져온다.

 

.skip 은 몇 개의 document를 건너뛸지를 정한다. 처음에는 페이지 1을 불러오므로 ((1-1) * 30) 처음부터 30개를 가져온다.

.limit은 몇 개의 document까지 가져올지를 정한다. skip한 이후부터 30개를 가져온다.


const NewChannel = () => {
  const [channels, setChannels] = useState([]);
  const [channelCount, setChannelCount] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);

channels 렌더링할 채널 리스트를 배열에 담는다.

channelCount 채널의 수와 페이지 수를 표시하는데 이용된다.

currentPage 현재 페이지를 query로 보내기 위해, 현재 페이지를 나타내기 위해 쓰인다.

 

  const requestChannelsAndSetStates = async (currentPage = 1, channelsPerPage = 30) => {
    try {
      const params = {
        page: currentPage,
        pageSize: channelsPerPage,
      };

      const response = await axios.get(API_ENDPOINTS.CHANNELS, { params });
      const { channels, channelCount } = response.data;
      setChannelsStates(channels, channelCount);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  const setChannelsStates = (channels, channelCount) => {
    setChannels(channels);
    setChannelCount(channelCount);
  };

requestChannelsAndSetStates 쿼리를 보내고, 해당 페이지에 해당하는 채널 데이터를 받아온다

 

  const paginationProps = {
    channelCount,
    currentPage,
    setCurrentPage,
  };

  return (
    <div className="channels container">
      <div className="new-channel">
        <Title subject={SUBJECT_VALUE} channelCount={channelCount} />
        <div className="channel-list">
          <Pagination {...paginationProps} />
          <ul>
            {channels.length ? (
              channels.map((channel) => <ChannelItem key={channel.channelId} channel={channel} />)
            ) : (
              <Loading />
            )}
          </ul>
          <Pagination {...paginationProps} />
        </div>
      </div>
    </div>
  );
};

페이지네이션 컴포넌트에 필요한 프롭스를 전달한다
channelCount 페이지 숫자를 계산하기 위해 이용된다.

currentPage setCurrentPage 페이지 쿼리 요청과 현재 페이지를 표시하기 위해 이용된다.

 

const Pagination = ({ channelCount, setCurrentPage, currentPage }) => {
  const pageNumbers = Array.from({ length: Math.ceil(channelCount / 30) }, (_, index) => index + 1);

  const handleClickPageNumber = (number) => {
    setCurrentPage(number);
    window.scrollTo({ top: 0, behavior: "auto" });
  };

  return (
    <nav className="page-navigator">
      <ul className="page-list">
        {pageNumbers.map((number) => {
          return (
            <li key={number} className="page-item">
              <button
                onClick={() => handleClickPageNumber(number)}
                className={`${currentPage === number ? "active" : null} page-button`}
              >
                {number}
              </button>
            </li>
          );
        })}
      </ul>
    </nav>
  );
};

export default Pagination;

페이지 숫자를 배열로 생성한다.

클릭 이벤트를 전달한다. => serCurrentPage(클릭한숫자)