강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

변재정님의 프로필 이미지
변재정

작성한 질문수

Next + React Query로 SNS 서비스 만들기

인피니트 스크롤링

useInfiniteQuery promise와 react use 사용시 페이지 무한 로딩

작성

·

40

0

리액트 쿼리의 suspense 스트리밍 기능 구현 중 버그가 발생해 인사이트를 얻고자 질문드립니다.

상위 컴포넌트에서 useInfiniteQuery로 promise를 반환하고, 해당 promise를 자식 컴포넌트의 props로 넘긴 뒤 React의 use hook으로 감싸서 data를 반환하도록 구현했습니다. 그리고 promise를 throw하는 자식 컴포넌트를 Suspense로 감싸서 promise를 캐치하도록 했는데요.

페이지 렌더링 자체는 정상적으로 되는데, request가 완료되지 않는 문제가 있습니다. 크롬 개발자도구의 Network 탭에서 document를 확인하면 "Caution: request is not finished yet"이라는 경고가 표시됩니다.

TanStack Query 공식 문서에도 useInfiniteQuery의 promise 사용 시 "This can be used with React.use() to fetch data"라고 명시되어 있어 React use와 함께 사용하라고 안내하고 있는데, 혹시 이 문제의 원인을 알 수 있을까요?

참고로 prefetch는 안했습니다. 그리고 prefetch 안하는 방법으로 suspense 스트리밍을 구현하고 싶습니다.

 

코드는 아래와 같습니다. 감사합니다!

 

export default function DetailReviewWrapper({ pid, userId }: DetailReviewProps) {
  const { infoData, observerRef, isFetchingNextPage, refetch, promise } = useReviewListInfinity({
    userId,
    pid,
  })
  return (
    <Suspense fallback={<DetailReviewLoading />}>
      <DetailReview
        pid={pid}
        userId={userId}
        promise={promise}
        refetch={refetch}
        isFetchingNextPage={isFetchingNextPage}
        observerRef={observerRef}
      />
    </Suspense>
  )
}
export default function DetailReview({
  pid,
  userId,
  promise,
  refetch,
  isFetchingNextPage,
  observerRef,
}: DetailReviewProps) {

  const data = use(promise)

  return (
    <>
      <section>
 <ReviewListView
          userId={userId}
          pid={pid}
          data={data?.list || []}
          className={cn('review-list')}
          refetch={refetch}
          showPoint
        />
        {isFetchingNextPage && <Loading />}
        <div ref={observerRef} />   
   </section>
export function useReviewListInfinity(params: UseReviewListInfinityProps) {
  const section = useSearchParams().get('contentType') as SectionType
  const orderType = useRecoilValue(commentOrderState)
  const filterType = useRecoilValue(filterTypeState)

  const { fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, refetch, promise } = useInfiniteQuery({
    queryKey: [REVIEW_LIST_KEY, params, orderType, filterType, section],
    queryFn: ({ pageParam = 1 }) =>
      getReviewApi({
        uid: params.userId,
        pid: params.pid,
        section,
        pageInfo: {
          curPage: pageParam,
          pageSize: 20,
        },
        orderType: orderType === 'RECOMMENDED' ? 'like' : 'date',
        filterType,
      }),
    select: (data) => {
      return {
        list: data.pages.flatMap((page) => page.data.list),
        info: data.pages[0].data.info,
      }
    },
    getNextPageParam: (lastPage) => {
      const nextPage = lastPage.data.pageInfo.curPage + 1
      return nextPage <= lastPage.data.pageInfo.pageCount ? nextPage : undefined
    },
    initialPageParam: 1,
  })

  const { observerRef } = useIntersectionObserver({
    onScroll: () => {
      if (hasNextPage && !isFetchingNextPage) {
        fetchNextPage()
      }
    },
  })

  return {
    isLoading,
    isFetchingNextPage,
    observerRef,
    refetch,
    promise,
  }
}
const getQueryClient = (): QueryClient =>
  new QueryClient({
    defaultOptions: {
      queries: {
        refetchOnWindowFocus: false,
        refetchInterval: false,
        refetchOnReconnect: true,
        refetchOnMount: true,
        staleTime: Infinity,
        gcTime: Infinity,
        retry: false,
        experimental_prefetchInRender: true,
      },
    },
  })

 

무한 로딩 시 개발자 도구 캡쳐이미지입니다.

 

스크린샷 2025-11-03 오후 5.42.48.png

 

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

useInfiniteQuery가 promise를 return하나요? 공식문서에서도 본 적이 없는 용법이라...

변재정님의 프로필 이미지
변재정
질문자

https://tanstack.com/query/latest/docs/framework/react/reference/useInfiniteQuery

요기 문서 보시면 promise를 return하는걸로 나와있긴 합니다. 근데 promise를 사용하는 레퍼런스가 많이 없긴 하더라구요...

 

const {
  fetchNextPage,
  fetchPreviousPage,
  hasNextPage,
  hasPreviousPage,
  isFetchingNextPage,
  isFetchingPreviousPage,
  promise,
  ...result
} = useInfiniteQuery({
  queryKey,
  queryFn: ({ pageParam }) => fetchPage(pageParam),
  initialPageParam: 1,
  ...options,
  getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) =>
    lastPage.nextCursor,
  getPreviousPageParam: (firstPage, allPages, firstPageParam, allPageParams) =>
    firstPage.prevCursor,
})

 

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

아, 깃헙 이슈에도 질문 올리셨군요. 실험적 기능이라 라이브러리 자체 버그 여부도 판단해봐야겠습니다.

변재정님의 프로필 이미지
변재정
질문자

앗 보셨군요ㅋㅋㅋㅋ

useInfiniteQuery promise 대신 useSuspenseInfiniteQuery 사용하니까 해결되긴 했습니다. 제로초님 답변처럼 실험적 기능에 의한 버그이지 않을까 싶네요

아무튼 빠른 답변 감사합니다!

변재정님의 프로필 이미지
변재정

작성한 질문수

질문하기