이번 프로젝트에서 유저 목록을 보여줄 때, Infinite Scroll
기법을 사용해서 데이터를 보여주기로 결정하였다. react-query
에 useInfiniteQuery
hook이 있어서 사용해보려고 했는데, 생각보다 공식문서 설명이 부족한 것 같아서 실제 코드를 가지고 정리해보려고 한다.
우선 공식문서에는 다음과 같이 나와있다.
const {
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
...result
} = useInfiniteQuery(queryKey, ({ pageParam = 1 }) => fetchPage(pageParam), {
...options,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
})
기타 부분은 useQuery
와 같지만 몇 가지 다른 점이 눈에 띈다.
page를 지정해준다. 기본값을 1로 한 상태에서 다음 데이터를 불러온다.
page를 1 증가시키는 역할을 한다.
실제 코드를 보며 확인해보겠다.
const useBlacklistQuery = () => {
// useInfiniteQuery에서 쓸 함수
const fetchBlacklist = async ({ pageParam = 1 }) => {
const response = await axiosInstance.get(
`/api/---/${pageParam}`,
);
const result = response.data;
// axios로 받아온 데이터를 다음과 같이 변경!
return {
result: result.blacklist,
nextPage: pageParam + 1,
isLast: result.is_last,
}; ❤
};
const query = useInfiniteQuery('[blacklist]', fetchBlacklist, {
getNextPageParam: (lastPage, pages) => {
if (!lastPage.isLast) return lastPage.nextPage;
return undefined;
},
refetchOnWindowFocus: false,
refetchOnMount: true,
refetchOnReconnect: true,
retry: 1,
});
return query;
};
여기서 핵심은 ❤ 부분이다.
우선, result의 구조는 다음과 같다.
result : {
blacklist : {
user1 : {
},
user2 : {
},
},
is_last : true,
}
유저 목록을 담은 부분과 마지막 여부를 (백엔드에서 계산해서) true / false로 담아준다.
이것을 쪼개서 새로운 객체로 리턴해준다.
return {
result : result.blacklist,
nextPage : pageParam + 1,
isLast : result.is_last,
}
여기 이 객체가 getNextPageParam
의 lastPage
로 넘어간다. 이 때, isLast
가 false라면 기존 page
에 +1 해준 nextPage
를 return 해주는 것이다.
이 nextPage는 컴포넌트에서 fetchNextPage
를 진행하면 새로운 pageParam으로 넘어가게 된다.
공식문서에는 다음과 같이 나와있다.
getNextPageParam : (lastPage, allPages) => unknown | undefined
It should return a single variable that will be passed as the last optional parameter to your query function.
Return undefined to indicate there is no next page available.