코드잇

무한스크롤 커스텀 hook

윤해용 2024. 6. 10. 21:12

서문

이전의 포스팅 중 하나인 [BLOB] 프로젝트 회고의 프로젝트에서 무한스크롤 구현하면서 발생한 문제와 이를 해결한 방식을 담고 있습니다.

 

구현

무한스크롤

데이터 가져오는 과정과 로딩 및 에러 처리를 쉽게 구현하기 위해 React Query의 useInfiniteQuery 훅 이용

ViewPort에 보여지는 요소를 체크하기 위해 react-intersection-observer의 useInView 훅 이용

 

 

처음 무한스크롤 훅 코드 부분

export default function useInfiniteQueries(variant: 'feedPage') {
  const queryKey = [variant];
  let queryFn;

  // variant에 따라 다른 queryFn을 사용
  if (variant === 'feedPage') {
    // eslint-disable-next-line prefer-const
    queryFn = ({ pageParam = 0 }) => getPosts(pageParam, POSTS_PAGE_LIMIT);
  }

  const {
    data: postsData,
    isPending,
    isError,
    fetchNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey,
    queryFn,
    initialPageParam: 0,
    getNextPageParam: (lastPage, allPages, lastPageParam: number) => (lastPage.hasMore ? lastPageParam + 1 : undefined),
  });

  return { postsData, isPending, isError, fetchNextPage, isFetchingNextPage };
}

 

 

페이지 별로 다른 queryFn을 설정해서 무한스크롤 훅을 구현했었다.

 

이후 팀원에게 코드 리뷰를 받았고, 

 

 

페이지가 많아질 경우 코드가 길어지는 문제를 해결할 필요가 있었다.

 

if문에 queryFn은 다른 곳에서 처리하고 무한스크롤 훅 부분에서는 무한스크롤에 관련된 코드만 작성하도록 했다.

export default function useInfiniteScrollQuery(queryOptions: {
  queryKey: readonly (string | number)[];
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  queryFn: (page: number) => Promise<any>;
}) {
  const { queryKey, queryFn } = queryOptions;

  const { ref, inView } = useInView();

  const { data, isPending, isError, fetchNextPage, isFetchingNextPage, refetch } = useInfiniteQuery({
    queryKey,
    queryFn: ({ pageParam }) => queryFn(pageParam),
    initialPageParam: 0,
    getNextPageParam: (lastPage, allPages, lastPageParam: number) =>
      lastPage.data.hasMore ? lastPageParam + 1 : undefined,
  });

  useEffect(() => {
    if (inView) {
      fetchNextPage();
    }
  }, [inView, fetchNextPage]);

  return { data, isPending, isError, fetchNextPage, isFetchingNextPage, ref, refetch };

 

 

무한 스크롤 hook 사용 부분 

export function useFetchNotificationList() {
  return useInfiniteScrollQuery({
    queryKey: notifications.all.queryKey,
    queryFn: (page: number) => getNotificationList({ page, size: POSTS_PAGE_LIMIT }),
  });
}

 

거의 모든 게시글과 댓글에서 무한 스크롤이 적용된다. 그렇기 때문에 어디서든 무한 스크롤을 사용할 수 있게 훅을 잘 만들어 두는게 중요했다. 어떻게 하면 팀원들이 무한스크롤 훅을 가져가서 잘 쓸 수 있을까? 어떻게 하면 코드 수를 줄일 수 있을까? 팀원들이 이해하기 쉽도록 구현하려고 노력했다.