데이터를 받아와서 리스트를 구현할 때, 처음 로딩 시간을 줄이고자 모든 데이터를 한 번에 받아오지 않고 여러 번에 나누어(스크롤 할 때마다) 가져오는 것을 구현하기 위해서 TanStack-query의 useInfiniteQuery() 훅을 사용해봤다.
const {
data,
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,
})
queryFn
initialPageParam
getNextPageParam
undefined 또는 null을 반환해야 함훅의 return 반환값
datadata.pagesdata.pageParams
export function Component() {
const observerRef = useRef();
const fetchPosts = async (page = 1, items = 10) => {
return await pb.collection('posts').getList(page, items);
};
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam }) => fetchPosts(pageParam),
initialPageParam: 1,
getNextPageParam: (lastPage, allPages) => {
if (lastPage.length < 10) return undefined;
return allPages.length + 1;
},
});
useEffect(() => {
if (!observerRef.current) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
},
{ threshold: 1.0 }
);
observer.observe(observerRef.current);
return () => {
if (observerRef.current) {
observer.unobserve(observerRef.current);
}
};
}, [fetchNextPage, hasNextPage, isFetchingNextPage]);
const allPosts = data?.pages.flat() || [];
return (
<div className={S.component}>
<Outlet context={{ posts: allPosts, isLoading }} />
<div ref={observerRef} style={{ height: '1px' }}></div>
</div>
);
}
fetchPosts 함수page는 몇 번째 페이지인지, items는 페이지당 데이터의 갯수를 나타냄page = 1, items = 10 일 경우, 0~9번 째 데이터를 가져오고, page = 2, items = 10 일 경우, 10~19번 째 데이터를 가져옴getNextPageParam
pageParam 매개변수가 있는지 확인page + 1을 nextPageParam으로 반환해서 다음 페이지를 가져옴fetchNextPage()
fetchPosts(nextPageParam)을 실행IntersectionObserver
fetchNextPage()를 실행