[TanStakQuery] 페이지네이션 / 지연 쿼리(Paginated / Lagged Queries)

Jeris·2023년 5월 22일
0

페이지네이션된 데이터를 렌더링하는 것은 매우 일반적인 UI 패턴이며, TanStack Query에서는 쿼리 키에 페이지 정보를 포함하면 "그냥 작동"합니다:

const result = useQuery({
  queryKey: ['projects', page],
  queryFn: fetchProjects
})

하지만 이 간단한 예제를 실행해 보면 이상한 점을 발견할 수 있습니다:

각각의 새 페이지가 완전히 새로운 쿼리처럼 취급되기 때문에 UI가 successloading 상태를 오가는 것입니다.

이러한 환경은 최적의 환경이 아니며, 안타깝게도 오늘날 많은 툴들이 이러한 방식을 고집하고 있습니다. 하지만 TanStack Query는 그렇지 않습니다! 이미 짐작하셨겠지만, TanStack Query에는 이 문제를 해결할 수 있는 keepPreviousData라는 멋진 기능이 함께 제공됩니다.

Better Paginated Queries with keepPreviousData

쿼리에 대해 페이지 인덱스(또는 커서)를 증가시키고자 하는 다음 예제를 생각해 보겠습니다. useQuery를 사용하면 기술적으로는 여전히 정상적으로 작동하지만, 각 페이지 또는 커서마다 다른 쿼리가 생성 및 소멸됨에 따라 UI가 success, loading 상태를 오가게 됩니다. keepPreviousDatatrue로 설정하면 몇 가지 새로운 기능이 추가됩니다:

  • 쿼리 키가 변경되었더라도 새 데이터가 요청되는 동안 마지막으로 성공적으로 fetch한 데이터를 사용할 수 있습니다.
  • 새 데이터가 도착하면 이전 data가 원활하게 교체되어 새 데이터가 표시됩니다.
  • 쿼리가 현재 어떤 데이터를 제공하고 있는지 알 수 있도록 isPreviousData를 사용할 수 있습니다.
function Todos() {
  const [page, setPage] = React.useState(0)

  const fetchProjects = (page = 0) => fetch('/api/projects?page=' + page).then((res) => res.json())

  const {
    isLoading,
    isError,
    error,
    data,
    isFetching,
    isPreviousData,
  } = useQuery({
    queryKey: ['projects', page],
    queryFn: () => fetchProjects(page),
    keepPreviousData : true
  })

  return (
    <div>
      {isLoading ? (
        <div>Loading...</div>
      ) : isError ? (
        <div>Error: {error.message}</div>
      ) : (
        <div>
          {data.projects.map(project => (
            <p key={project.id}>{project.name}</p>
          ))}
        </div>
      )}
      <span>Current Page: {page + 1}</span>
      <button
        onClick={() => setPage(old => Math.max(old - 1, 0))}
        disabled={page === 0}
      >
        Previous Page
      </button>{' '}
      <button
        onClick={() => {
          if (!isPreviousData && data.hasMore) {
            setPage(old => old + 1)
          }
        }}
        // Disable the Next Page button until we know a next page is available
        disabled={isPreviousData || !data?.hasMore}
      >
        Next Page
      </button>
      {isFetching ? <span> Loading...</span> : null}{' '}
    </div>
  )
}

Lagging Infinite Query results with keepPreviousData

일반적이지는 않지만, keepPreviousData 옵션은 useInfiniteQuery 훅과도 완벽하게 작동하므로 무한 쿼리 키가 시간이 지남에 따라 변경되는 동안 사용자가 캐시된 데이터를 계속 볼 수 있도록 지원합니다.

Reference

profile
job's done

0개의 댓글