진행 중인 프로젝트에서 useInfiniteQuery 훅과 useInview훅을 이용해서 무한스크롤을 간단하게 구현했다.
const {
data,
isFetching,
hasNextPage,
fetchNextPage,
isFetchingNextPage
} = useInfiniteQuery<Project[]>({
queryKey: ['projectList'],
queryFn: ({ pageParam }) => getProjectList({ pageStart: pageParam, size: SIZE_PER_PAGE }),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) => {
const nextPage = allPages.length;
return lastPage.length < SIZE_PER_PAGE ? undefined : nextPage;
},
retry: 0,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
});
• initialPageParam
: 초기 pageParam값을 결정하는 필수 요소이다.
• getNextPageParam
: getNextPageParam이 반환 하는 값은 pageParam으로 queryFn
의 매개변수로 쓰인다. pageParam이 존재하면 hasNextPage가 true로 설정된다.
마지막 페이지의 데이터가 SIZE_PER_PAGE
(한 페이지에 담을 데이터의 최대 개수)보다 작으면 마지막 페이지로 인지하고 pageParam값을 정의하지 않도록 했다. useInfiniteQuery는 pageParam이 undefined 혹은 null이면 더 이상 데이터를 요청하지 않는다.
• lastPage
: queryFn
에서 반환된 가장 최근의 데이터 페이지로, 아래와 같이 배열 형태로 데이터가 포함되어 있다. lastPage
의 길이는 한 페이지에 담긴 데이터 객체의 개수를 나타낸다.
[
{ "id": 3, "name": "Project 3", "description": "Description 3" },
{ "id": 4, "name": "Project 4", "description": "Description 4" }
]
• allPages
: 지금까지 불러온 모든 페이지의 데이터가 배열에 담겨 있다. allPages
의 길이는 현재까지 불러온 페이지의 수를 나타낸다.
[
[
{ "id": 1, "name": "Project 1", "description": "Description 1" },
{ "id": 2, "name": "Project 2", "description": "Description 2" }
],
[
{ "id": 3, "name": "Project 3", "description": "Description 3" },
{ "id": 4, "name": "Project 4", "description": "Description 4" }
]
]
여기부터는 옵션 설정이다.
• retry
: 쿼리 실패 시 재시도 횟수를 설정한다. 나는 0으로 설정하였다.
• refetchOnReconnect
: 네트워크 재 연결 시 데이터를 다시 불러올지 설정한다.
• refetchOnWindowFocus
: 창이 다시 포커스될 때 데이터를 다시 불러올지 설정한다.
그 다음 useInView
훅을 사용하여 사용자가 마지막 요소에 도달했을 때 다음 페이지를 불러오도록 설정했다.
const { ref, inView } = useInView();
useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [hasNextPage, fetchNextPage, inView]);
<div ref={ref} />
• ref
: Intersection Observer가 관찰할 요소이다. useInfiniteQuery로 가져온 데이터들이 보여지는 맨 밑영역에 ref
를 가진 빈 div
요소를 할당하였다.
• inView
: 관찰 대상 요소가 뷰포트(사용자의 화면 영역) 내에 있는지 여부를 나타내는 boolean 값이다. Intersection Observer는 관찰 요소가 뷰포트와 교차할 때 이를 감지하여 inView
를 true
로 바꾸고, 벗어나면 false
가 바꾼다.
따라서 사용자의 스크롤이 데이터의 맨 아래를 넘어가고, 데이터가 있는 다음 페이지가 존재하면 fetchNextPage 함수를 호출하여 다음 페이지의 데이터를 불러오게 되어 무한 스크롤이 적용된다.
진행 중인 프로젝트에서 useInfiniteQuery 훅과 useInview훅을 이용해서 무한스크롤을 간단하게 구현했다.
const {
data,
isFetching,
hasNextPage,
fetchNextPage,
isFetchingNextPage
} = useInfiniteQuery<Project[]>({
queryKey: ['projectList'],
queryFn: ({ pageParam }) => getProjectList({ pageStart: pageParam, size: SIZE_PER_PAGE }),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) => {
const nextPage = allPages.length;
return lastPage.length < SIZE_PER_PAGE ? undefined : nextPage;
},
retry: 0,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
});
• initialPageParam
: 초기 pageParam값을 결정하는 필수 요소이다.
• getNextPageParam
: getNextPageParam이 반환 하는 값은 pageParam으로 queryFn
의 매개변수로 쓰인다. pageParam이 존재하면 hasNextPage가 true로 설정된다.
마지막 페이지의 데이터가 SIZE_PER_PAGE
(한 페이지에 담을 데이터의 최대 개수)보다 작으면 마지막 페이지로 인지하고 pageParam값을 정의하지 않도록 했다. useInfiniteQuery는 pageParam이 undefined 혹은 null이면 더 이상 데이터를 요청하지 않는다.
• lastPage
: queryFn
에서 반환된 가장 최근의 데이터 페이지로, 아래와 같이 배열 형태로 데이터가 포함되어 있다. lastPage
의 길이는 한 페이지에 담긴 데이터 객체의 개수를 나타낸다.
[
{ "id": 3, "name": "Project 3", "description": "Description 3" },
{ "id": 4, "name": "Project 4", "description": "Description 4" }
]
• allPages
: 지금까지 불러온 모든 페이지의 데이터가 배열에 담겨 있다. allPages
의 길이는 현재까지 불러온 페이지의 수를 나타낸다.
[
[
{ "id": 1, "name": "Project 1", "description": "Description 1" },
{ "id": 2, "name": "Project 2", "description": "Description 2" }
],
[
{ "id": 3, "name": "Project 3", "description": "Description 3" },
{ "id": 4, "name": "Project 4", "description": "Description 4" }
]
]
여기부터는 옵션 설정이다.
• retry
: 쿼리 실패 시 재시도 횟수를 설정한다. 나는 0으로 설정하였다.
• refetchOnReconnect
: 네트워크 재 연결 시 데이터를 다시 불러올지 설정한다.
• refetchOnWindowFocus
: 창이 다시 포커스될 때 데이터를 다시 불러올지 설정한다.
그 다음 useInView
훅을 사용하여 사용자가 마지막 요소에 도달했을 때 다음 페이지를 불러오도록 설정했다.
const { ref, inView } = useInView();
useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage();
}
}, [hasNextPage, fetchNextPage, inView]);
<div ref={ref} />
• ref
: Intersection Observer가 관찰할 요소이다. useInfiniteQuery로 가져온 데이터들이 보여지는 맨 밑영역에 ref
를 가진 빈 div
요소를 할당하였다.
• inView
: 관찰 대상 요소가 뷰포트(사용자의 화면 영역) 내에 있는지 여부를 나타내는 boolean 값이다. Intersection Observer는 관찰 요소가 뷰포트와 교차할 때 이를 감지하여 inView
를 true
로 바꾸고, 벗어나면 false
가 바꾼다.
따라서 사용자의 스크롤이 데이터의 맨 아래를 넘어가고, 데이터가 있는 다음 페이지가 존재하면 fetchNextPage 함수를 호출하여 다음 페이지의 데이터를 불러오게 되어 무한 스크롤이 적용된다.