[TanStack Query] 무한스크롤 기능 구현

zzincode·2025년 2월 10일
0

ReviewZIP

목록 보기
3/8
post-thumbnail

TanStack Query를 활용한 무한스크롤

기본 세팅은 해당 링크를 참고


¹ 불러오고자 하는 데이터 API² 끝에 도달했을 때 api를 호출하는 트리거 요소(.spinner>ClipLoader) 세팅

<div className="MainPage">
	  <Header header={'영화'} />
	  {data.pages.map((page, i) => (
	    <MovieList key={i} list={page.results} />
	  ))}
	  <div className="spinner">
	    <ClipLoader color="#5db996" ref={ref} />
	  </div>
</div>

무한스크롤 기능을 구현하는 커스텀 훅 생성

useInfiniteQuery 훅 : 여러 페이지의 데이터를 관리하고, 다음 페이지를 요청하는 기능을 제공

  • getNextPageParam : 다음 페이지를 요청할 때 사용할 페이지 번호를 결정하는 함수
  • initialPageParam : 처음 쿼리를 시작할 때 사용할 페이지 번호
const fetchMovie = async page => {
  return fetchFromApi(`/movie/now_playing?language=ko-KR&page=${page}`);
};
const useInfiniteScroll = () => {
  return useInfiniteQuery({
    queryKey: ['now-playing'],
    queryFn: ({ pageParam }) => {
      return fetchMovie(pageParam);
    },
    getNextPageParam: last => {
      if (last.page < last.total_pages) {
        return last.page + 1;
      }
      return undefined;
    },
    initialPageParam: 1,
  });
};

export default useInfiniteScroll;

데이터 불러오기

const {
    data,
    isLoading,
    error,
    fetchNextPage,
    hasNextPage,
    isFetchNextPage
  } = useInfiniteScroll();
  
  return (
    <div className="MainPage">
      <Header header={'영화'} />
      {data?.pages.map((page, i) => (
        <MovieList key={i} list={page.results} />
      ))}
      <div className="spinner">
        <ClipLoader/>
      </div>
    </div>
  );
  

fetchNextPage: 다음 페이지 결과 가져오기

hasNextPage : 다음에 가져올 페이지가 있는지에 대한 여부(t/f)

isFetchNextPage : 다음 페이지를 가져오는 동안 true

react-intersection-observer

React 애플리케이션에서 Intersection Observer API를 쉽게 사용할 수 있도록 도와주는 라이브러리

→ 요소가 뷰포트에 들어오거나 나갈 때를 감지할 수 있음

설치

$ npm i react-intersection-observer

사용 예시

뷰포트에 들어왔는지 감지할 요소에 ref 지정

  const { ref, inView } = useInView();
  
  return (
        <ClipLoader color="#5db996" ref={ref} />
  );
  
  

전체 적용 코드

const Main = () => {
  const {
    data,
    isLoading,
    error,
    fetchNextPage,
    hasNextPage,
    isFetchNextPage
  } = useInfiniteScroll();

  const { ref, inView } = useInView();
  
  useEffect(() => {
    if (inView && hasNextPage && !isFetchNextPage) {
      fetchNextPage();
    }
  }, [inView]);

  if (isLoading) {
    return <div>Loading</div>;
  }
  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return (
    <div className="MainPage">
      <Header header={'영화'} />
      {data?.pages.map((page, i) => (
        <MovieList key={i} list={page.results} />
      ))}
      <div className="spinner">
        <ClipLoader color="#5db996" ref={ref} />
      </div>
    </div>
  );
};

export default Main;
  1. spinner의 로딩바에 react-intersection-observer의 ref를 연결해주면 로딩바 영역이 viewport안에 들어오면서 inView 값이 true가 된다.

    다음 데이터를 가져오면 스크롤이 생기면 로딩바 영역이 viewport를 벗어나며 inView 값이 false가 됨

  2. useEffect로 inView값이 변화 될 때 inView값과 다음 페이지가 있을 때와 다음 페이지를 가져오는 값이 모두 true fetchNextPage 함수가 실행되도록한다


✅ 정리

  1. tanstack-query , react-intersection-oberver 라이브러리 설치
  2. tanstack-query의 useinfinteQuery 훅으로 무한 스크롤 기능 커스텀 훅 생성 - 데이터 API 연결 및 API 속 페이지 넘어가는 코드 작성
  3. 무한스크롤 적용할 페이지에 무한스크롤 커스텀 훅으로 데이터 불러오며
    react-intersection-observer의 ref를 활용하여 뷰포트 들어왔음을 감지해 다음 페이지로 넘어가게 하기

0개의 댓글