[42gg] 무한스크롤 구현

Daehyun·2022년 7월 23일
1

42gg

목록 보기
2/8
post-thumbnail

프로젝트에서 처음 주어진 과제는 랭킹 페이지 구현이었다.
랭크 리스트는 무한 스크롤이나 페이지네이션 등을 통해 나타낼 수 있다.
이번 포스트에서는 무한 스크롤 구현에 대해 설명한다.

무한 스크롤

  • 무한 스크롤을 구현하기 위해 React Query을 사용한다.
    리액트 쿼리는 서버의 값을 클라이언트에 가져오거나 캐싱, 값 업데이트, 에러핸들링 등 비동기 과정을 더욱 편하게 하는데 사용한다.

  • 리액트 쿼리를 사용하려면 컴포넌트를 QueryClientProvider로 감싸주어야 한다.

    import { QueryClient, QueryClientProvider } from "react-query";
    import RankList from '../components/rank/RankList';
    
    export default function Rank() {
     const queryClient = new QueryClient();
    
     return (
       <QueryClientProvider client={queryClient}>
         <RankList />
       </QueryClientProvider>
     );
    }

  • RankList컴포넌트 내부에서 데이터를 불러오고, 다음 페이지의 데이터를 불러오는 과정을 구현한다.

    import axios from 'axios';
    import React, { useEffect } from 'react';
    import { Rank, RankData } from '../../types/rankTypes';
    import infScroll from '../../utils/infinityScroll';
    import { useInfiniteQuery } from 'react-query';
    import InfiniteScroll from 'react-infinite-scroll-component';
    
    const END_POINT = 'http://localhost:3000/api';
    
    export default function infScroll(path: string) {
      
     // pageParam은 useInfiniteQuery의 getNextPageParam에서 자동으로 넘어온다. 
     // 1페이지는 undefined로 아무것도 넘어오지 않는다. 초기값을 반드시 설정하자. 
     const getRankList = ({ pageParam = 1 }) =>
       axios
         .get(`${END_POINT}${path}${pageParam}`, {})
         .then((res) => res?.data);
    
     const result = useInfiniteQuery('rankList', getRankList, {
             // 💡 중요! getNextPageParams가 무한 스크롤의 핵심,
             // getNextPageParam 메서드가 falsy한 값을 반환하면 추가 fetch를 실행하지 않는다
             // falsy하지 않은 값을 return 할 경우 Number를 리턴해야 하며
             // 위의 fetch callback의 인자로 자동으로 pageParam을 전달.
       getNextPageParam: (lastPage, pages) => {
         if (lastPage.info.next === 'null') return false;
         return pages.length + 1;
       },
     });
     return result;
    }
    
    export default function RankList() {
      const result = infScroll('/pingpong/ranks/');
      const { data, // 💡 data.pages를 갖고 있는 배열
             fetchNextPage, // 💡 다음 페이지를 불러오는 함수
             hasNextPage, // 다음 페이지가 있는지 여부, Boolean
             status // 💡 loading, error, success 중 하나의 상태, string 
            } = result;
    
      return (
      <>
         <InfiniteScroll
           dataLength={data?.pages.length! * 8}
           next={fetchNextPage}
           hasMore={hasNextPage!}
           loader={<h4>Loading...</h4>}
         >
           <div className={styles.title}>Ranking</div>
           <div className={styles.container}>
      		... 중략 ...
             </div>
             {status === 'success' && (
               <>
                 {data?.pages.map((group, index) => (
             ... 중략 ...
                 ))}
               </>
             )}
           </div>
         </InfiniteScroll>
       </>
     );
    }

생각해보기

  • 현재 구현된 무한 스크롤에는 데이터가 변경될 때 중복 또는 누락의 문제가 발생한다. (e.g 10개씩의 데이터를 불러올 경우 10등이 11등이 되면 기존 10위와 새로 불러온 데이터의 11위가 중복)
    -> 소켓 통신 등의 실시간 통신을 하지 않고 정적인 데이터를 주고 받기 때문에 발생하는 문제다. 하여 무한스크롤보다는 페이지네이션으로 문제 발생을 최소화하기로 했다.

  • 데이터가 많아져서 해당 순위까지 이동하는데 소요되는 시간이 길어진다.
    -> 마찬가지로 페이지네이션으로 구현하면 문제를 해결할 수 있다.

  • 결론은 무한스크롤에서 페이지네이션으로 바꾸기로 결정되었다. 무한스크롤은 다음 버전 출시 때 사용하기로 했다.

참고

https://velog.io/@hdpark/React-Query%EC%99%80-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-Next.js-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4

0개의 댓글