FE/React

[FE / REACT] Next.JS + TypeScript 무한스크롤 구현하기 (+React Query)

따봉치치 2024. 2. 6. 10:52
728x90

안녕하세요

오늘은 Next.JS(v.13) + TypeScript 환경에서 무한스크롤 구현하는 방법에 대해 알아보겠습니다

 

배경..

 

프로젝트에서 숙박 아이템을 확인할 수 있는 리스트를 구현하는데

모든 아이템을 한번에 가져와서 보여줄 수도 있지만

그렇게 하면 초기 렌더링 속도가 늘어나는 단점이 있어

무한스크롤로 구현하였습니다!

 

 

 

무한스크롤 구현하기!

 

 

1. 서버로 부터 받는 데이터 정의

 

처음 무한스크롤을 구현한다고 백엔드 분께 얘기했을 때

백엔드 분들께서 그럼 데이터를 어떤 형식으로 보내줘야 하냐고 여쭤보셨습니다

 

무한스크롤에 필요한 데이터는 다음과 같습니다

  • 실제 아이템 리스트 데이터
  • 현재 페이지 넘버
  • 다음 페이지가 존재하는지 boolean 값

 

2. 무한스크롤 구현

 

저는 React Query에서 useInfiniteQuery 훅을 사용해 주었습니다!

 

queryKey에 필터링 키워드도 함께 넣어줌으로 변수들의 값이 변경되었을 때마다 쿼리가 재갱신 될수 있도록 하였습니다.

initialPageParam에는 첫 페이지 번호를 넣어주면 됩니다. 서버 측에 초기  페이지 넘버값이 1로 되어있기 때문에 1로 선언해주었습니다

getNextPageParam에서는 다음으로 가져올 페이지 번호를 결정할 수 있습니다. 만약 lastPage 길이가 0이면 더이상 가져올 값이 없기 때문에 undefined를 반환해주었습니다

 const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
    queryKey: ['messages', filter, region],
    queryFn: ({ pageParam }) =>
      getCatchItemsListForScroll({ dataType, pageParam, filter, region }),
    initialPageParam: 1,
    getNextPageParam: (lastPage, allPages, lastPageParam) => {
      if (lastPage.list.length === 0) {
        return undefined;
      }

      return lastPageParam + 1;
    },
  });

 

 

3. 무한스크롤 적용할 요소 생성

 

무한스크롤을 구현하려면 스크롤 이벤트나 ref로 페이지 바닥을 감지해 계속해서 호출하는 방법도 있습니닫!

하지만 저는 react-infinite-scroll-component 라이브러리를 사용해주었습니다

그 이유는 ref로 마지막 요소를 감지하고 싶었으나 아이템 자체가 공통 컴포넌트로 사용이 되고 있었기 때문에

하나의 ref만을 걸 수가 없었습니다

 

따라서 react-infinite-scroll-component 라이브러리의 InfiniteScroll 컴포넌트를 사용해 구현하였습니다

 

<InfiniteScroll
      dataLength={data?.pages.length || 0}
      next={fetchNextPage}
      hasMore={hasNextPage}
      scrollableTarget="scrollableDiv"
      loader={<div className="loader" key={0}></div>}
    >
      <div
        id="scrollableDiv"
        className="w-full max-h-[calc(100vh-128px)] overflow-auto flex flex-col mt-[128px] gap-12 px-6 pt-2"
      >
        {' '}
        {data ? (
          data.pages.map((page, pageIndex) => (
            <div key={pageIndex} className="flex flex-col gap-8">
              {page.list.map((item: catchItems) => (
                <CatchSpecialComponent
                  key={item.productId}
                  accommodationName={item.accommodationName}
                  pageHandler={() => pageHandler(item.productId!)}
                  roomName={item.roomName}
                  checkIn={item.checkIn}
                  checkOut={item.checkOut}
                  originalPrice={item.originalPrice}
                  discountRate={item.discountRate}
                  sellPrice={item.sellPrice}
                  catchType={item.catchType}
                  image={item.image}
                />
              ))}
            </div>
          ))
        ) : (
          <></>
        )}
      </div>
    </InfiniteScroll>

 

InfiniteScroll을 사용해 실제 아이템을 감싸주면 ref를 따로 사용하지 않고도 무한스크롤을 구현해줄 수 있습니다!

 

 

728x90