Tanstack Query 무한 스크롤

유의진·2024년 12월 31일
0

찍찍이

목록 보기
4/6
post-thumbnail

무한 스크롤이란?

콘텐츠를 한 번에 로드하지 않고, 사용자가 페이지를 아래로 스크롤할 때 필요한 만큼만 추가로 로드하는 방식

특징

  • 스크롤 동작만으로 콘텐츠가 자동으로 로드
  • 추가적인 조작 없이 콘텐츠 탐색 가능
  • 데이터 로드 타이밍과 로딩 상태 표시가 중요

장점

  • 사용자 경험 향상: 스크롤만으로 새로운 콘텐츠를 볼 수 있어 간편함
  • 탐색 시간 단축: 여러 페이지를 오가며 데이터를 확인할 필요가 없음
  • 모바일 친화적: 작은 화면에서 페이지 버튼 대신 자연스러운 탐색 가능

적용

목표 상세 데이터 불러오기 코드

const GoalsDetailOptions = (): UseInfiniteQueryOptions<
  GoalsDetailResponse,
  AxiosError,
  BaseInfiniteQueryResponse<GoalsDetailResponse[]>
> => ({
  queryKey: [QUERY_KEYS.ALL_GOALS],
  queryFn: ({ pageParam = 0 }) =>
    GET<GoalsDetailResponse>(
      `${API_ENDPOINTS.GOAL.ALL_GOALS}?lastGoalId=${pageParam}&size=5`,
    ),
  getNextPageParam: (lastPage) => {
    const nextCursor = lastPage.data.nextCursor;
    return nextCursor !== 0 ? nextCursor : undefined;
  },
  initialPageParam: 0,
});

export const useGoalsDetailQuery = () => {
  const { data, ...etc } = useInfiniteQuery(GoalsDetailOptions());
  const goals = data?.pages.flatMap((page) => page.data.content) ?? [];

  return { goals, ...etc };
};

queryFn

lastGoalId값을 포함해 5개의 데이터를 불러온다.
size 값에 따라 몇 개의 목표를 가져올 것인지 설정한다.

getNextPageParam

마지막 데이터의 nextCursor 값을 가지고 pageParam 값을 설정해준다.
nextCurosr의 값이 null이면 pageParamundefined로 설정하여 추가 요청을 불러오지 않는다.

initialPageParam

초기 pageParam 값을 설정한다.

공통 무한 스크롤 custom hook

import { useEffect, useRef } from 'react';

interface InfiniteScrollProps {
  fetchNextPage: () => void;
  isLoading: boolean;
}

export const useInfiniteScroll = ({
  fetchNextPage,
  isLoading,
}: InfiniteScrollProps) => {
  const observerRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (!observerRef.current) return;

    const observerCallback: IntersectionObserverCallback = (entries) => {
      const lastEntry = entries[0];
      if (lastEntry.isIntersecting && !isLoading) {
        fetchNextPage();
      }
    };

    const observer = new IntersectionObserver(observerCallback, {
      threshold: 1.0,
    });

    if (observerRef.current) {
      observer.observe(observerRef.current);
    }

    observer.observe(observerRef.current);

    return () => observer.disconnect();
  }, [fetchNextPage, isLoading]);

  return {
    observerRef,
  };
};

Intersection Observer를 사용해 무한 스크롤을 구현하였다.

  • observerCallBack을 통해 마지막 요소가 뷰포트에 들어왔는지 감지
  • isintersecting 값이 true이고, 데이터 로드 중이 아니라면 fetchNextPage를 호출





참고

올리브영 테크블로그
https://oliveyoung.tech/2023-10-04/useInfiniteQuery-scroll/
무한 스크롤 장단점
https://brunch.co.kr/@joohyup1001/50

profile
안녕하세요. 프론트엔드 개발 공부를 하고 있습니다.

0개의 댓글

관련 채용 정보