일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- happy hacking
- 실행컨텍스트
- 정적스코프
- lexical environment
- moment.js
- variable object
- JavaScript
- Execution Context
- This
- Arrow function
- 함수
- webstorm
- function 표현식
- 리액트 라우터
- react-router
- hoisting
- activation object
- 객체
- type
- function 문
- scope chain
- 자바스크립트
- lexical scope
- 화살표 함수
- 호이스팅
- vs code
- 함수 표현식
- react router
- function
- BIND
- Today
- Total
Pandaman Blog
[React Query] Pagination과 Infinite Scroll 본문
1. Pagination
https://codesandbox.io/s/pagination-yeje-zcs5yh
React Query를 사용하면서 Pagination 구현을 어떻게 할 수 있을까? 사실 매우 간단하다.
useQuery(["projects", page])
단지 query key에 page 정보를 포함시킨다. page에 대한 데이터가 변경할 때마다 적용된 API를 fetch 할 것이다.
1.1. keepPreviousData 옵션
keepPreviousData 옵션을 true로 설정한 경우, 새 데이터가 요청되는 동안 마지막으로 성공적으로 가져온 데이터를 화면에 유지시켜 준다.
사실 설명으로 이해가 잘 안 되었다면 keepPreviousData 옵션을 off 시키고 페이지가 변경될 때의 화면을 살펴보자.
const { data, isLoading, isPreviousData } = useQuery(
["projects", page],
() => fetchProjects(page),
{
staleTime: 5000,
keepPreviousData: false,
select: (data) => {
return {
projects: data.projects,
hasMore: data.totalPages > page
};
}
}
);
return (
<div>
<p>페이지네이션 예제</p>
isPreviousData: {String(isPreviousData)}
<div>
{isLoading
? "Loading.."
: data.projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</div>
위와 같이 Loading 중인 경우는 "Loading.."
이라는 문구를 노출시키며 데이터가 settle 된 경우 프로젝트 리스트를 노출시킨다. 페이지가 변경될 때마다. 캐시 된 데이터가 없다면 Loading 중인
경우 이전 데이터를 나타내는 리스트는 화면에서 없어지고 "Loading.."
문구가 노출된다. 다시 새 데이터를 가져오면 새 리스트를 노출시킨다. keepPreviousData를 true로 변경하면 이전 데이터가 존재한다면, 새 데이터를 불러오기 전까지 이전 데이터를 유지시켜 준다. 사용자 관점에서 화면이 일관성 있게 유지되고 데이터만 변경되는 것이 더 자연스럽지 않을까 하는 생각이 들었다.
1.2. prefetchQuery
예제를 자세히 보면 prefetchQuery를 사용하고 있다. 그렇다면 prefetchQuery는 무엇일까?
이미 예상했겠지만, 데이터를 미리 가져와 캐시 하는 역할을 한다. 그렇다면 언제, 왜 필요할까?
아래는 예제 일부 코드이다. useEffect hook의 dependency을 보니 page
가 변경될 때 ["projects", page + 1]
쿼리, 즉 다음 페이지의 쿼리를 프리 패칭 하는 것이다.
React.useEffect(() => {
if (data?.hasMore) {
queryClient.prefetchQuery(["projects", page + 1], () =>
fetchProjects(page + 1)
);
}
}, [data, page, queryClient]);
prefetchQuery을 사용하면 다음 페이지로 이동할 때 이미 다음 페이지의 데이터를 캐시 하고 있어, 기다리는 시간 없이 바로 화면에 렌더링 되겠구나!라는 생각이 든다. 아주 좋은 기법이다.
2. Infinite Scroll
https://codesandbox.io/s/infinite-scroll-yeje-ecsyot?file=/pages/index.js:596-614
Infinite Scroll 도 많이 사용하는 기능이다. 보통 Intersection Observer API를 통해서 타깃과 교차되는 시점에 다음 페이지를 fetching 한다. 예제도 역시 동일하다. 여기서 우리는 react-query의 useInfiniteQuery
를 사용할 것이다.
const {
data,
isFetchingNextPage,
hasNextPage,
fetchNextPage,
} = useInfiniteQuery(
"projects",
async ({ pageParam = 0 }) => {
const res = await axios.get("/api/projects?cursor=" + pageParam);
return res.data;
},
{
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined
}
);
위에서 본 Pagination의 useQuery과 사용법이 약간 다르다. useInfiniteQuery
의 첫 번째 인자는 동일하게 queryKey이고, 두 번째 인자는 queryFn이다. 이때 queryFn의 인자로 pageParam 이 전달된다. 여기서 초기값은 0으로 설정했다(pageParam = 0).
1.1. getNextPageParam
해당 쿼리가 새 데이터를 받으면 getNextPageParam
는 마지막 페이지에 대한 데이터와 전체 페이지 리스트를 인자로 받는다(lastPage, allPages) => unknown | undefined
). return 하는 값으로 다음 페이지를 결정한다. 즉 다음 fetch 때의 pageParam를 결정한다. 만약 undefined를 반환한다면 다음 페이지는 존재하지 않다고 인식하여, 더 이상 fetch 하지 않는다.
여기서 우리는 현재의 페이지가 마지막 페이지인지, 다음 페이지가 존재하는지 파악해야 한다. lastPage.last_page === allPages.length 인 경우는 allPages.length + 1 반환, 아니면 undefined를 반환하여 마지막 페이지임을 알려준다.
(참고로 lastPage.last_page의 last_page는 api로 내려온 속성이다. 전체 페이지가 얼마나 되는지는 api를 통해서 알아야 한다..)
1.2. fetchNextPage
다음 페이지의 데이터를 가져올 때 사용한다. 보통 타깃이 intersection 되었을 때 fetchNextPage
를 호출하도록 설계한다.
1.3. hasNextPage
다음 페이지가 존재하는지 여부를 나타내며, getNextPageParam
에서 반환한 값이 undefined 이면 false 아니면 true 가 된다.
'Front end > React-Query' 카테고리의 다른 글
[React Query] Default Query Function (0) | 2022.05.15 |
---|---|
[React Query] Query / Mutation 이해하기 (0) | 2022.04.11 |