무한 스크롤을 구현하여 기본 데이터에 추가 데이터를 덧붙이는 형태의 UI 패턴은 매우 일반적 입니다.
react-query 는 이러한 유형의 목록을 쿼리하기 위해 useInfiniteQuery
를 지원합니다.
data
는 무한 쿼리 데이터를 포함하는 객체data.pages
가져오는 페이지들을 포함하는 배열data.pageParams
페이지를 가져오는 데 사용하는 파라미터를 포함하는 배열fetchNextPage
,fetchPreviousPage
이전, 다음 페이지를 불러오는 함수getNextPageParam
,getPreviousPageParam
옵션은 가져올 수 있는 데이터가 있을 경우 사용 가능.hasNextParam
을 사용할 수 있고getNextPageParam
의 반환값이undefined
가 아니면true
isFetchingNextPage
,isFetchingPreviousPage
를 사용하여 백그라운드 새로고침 상태와 추가 로딩 상태를 구분 가
{% hint style="info" %}
initialData
같은 옵션을 사용하는 경우 데이터를 재구성할 때 data.pages
, data.pagaParams
속성이 여전히 포함되어 있는지 확인해야 합니다. 그렇지 않으면 반드시 쿼리가 변경사항을 덮어씁니다 !
{% endhint %}
커서 인덱스를 기반으로 한번에 3페이지를 가져오는 API가 있다고 가정해보겠습니다.
fetch('/api/projects?cursor=0');
// { data: [...], nextCursor: 3}
fetch('/api/projects?cursor=3');
// { data: [...], nextCursor: 6}
fetch('/api/projects?cursor=6');
// { data: [...], nextCursor: 9}
fetch('/api/projects?cursor=9');
이 정보를 가지고, 우리는 무한 스크롤 UI 를 만들 수 있습니다.
import { useInfiniteQuery } from 'react-query'
function Projects() {
const fetchProjects = ({ pageParam = 0 }) => fetch('/api/projects?cursor=' + pageParam);
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
status,
} = useInfiniteQuery('projects', fetchProjects, {
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
});
return status === 'loading' ? (
<p>Loading...</p>
) : status === 'error' ? (
<p>Error: {error.message}</p>
) : (
<>
{data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.projects.map(project => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? 'Loading more...'
: hasNextPage
? 'Load More'
: 'Nothing more to load'}
</button>
</div>
<div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
</>
)
}
무한 쿼리가 오래된(stale) 상태가 되서 다시 가져와야 하는 경우엔 처음부터 순차적으로 다시 가져옵니다.
이렇게되면 기본 데이터가 변경되더라도 오래된 커서를 사용하지 않고, 데이터가 중복되거나 건너뛸 일이 생기지 않습니다.
무한 쿼리의 결과가 queryCache
에서 제거되면 페이지네이션은 처음부터 다시 시작됩니다.
기본적으로 getNextPageParam
에서 반환된 변수가 쿼리 함수에 제공되지만, 때에 따라서 이를 재정의 할 수 있습니다.
fetchNexPage
함수에 커스텀 변수를 전달할 수 있고, 이는 기본 변수를 재정의 합니다.
function Projects() {
const fetchProjects = ({ pageParam = 0 }) => fetch('/api/projects?cursor=' + pageParam);
const {
status,
data,
isFetching,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
} = useInfiniteQuery('projects', fetchProjects, {
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
});
// Pass your own page param
const skipToCursor50 = () => fetchNextPage({ pageParam: 50 });
}
양방향 무한 스크롤은 getPreviousPageParam
, fetchPreviousPage
, hasPreviousPage
, isFetchingPreviousPage
를 사용하여 구현 할 수 있습니다.
useInfiniteQuery('projects', fetchProjects, {
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, pages) => firstPage.prevCursor,
});