티스토리 뷰
[영화 목록 조회 프로젝트] React-Query의 useInfiniteQuery로 무한 스크롤링 기능 구현
doeunnkimm 2023. 4. 3. 11:34
🚀 React-Query의 useInfiniteQuery로 무한 스크롤 기능 구현
이번 글에서는 무한 스크롤 기능을 구현해 보려고 합니다. 무한 스크롤은 페이지네이션을 위한 api를 통해 page와 관련된 파라미터를 연속적으로 넘기면서 계속 데이터를 받아오고 이어서 화면에 보여주는 로직으로 작동되게 됩니다.
우선 React-Query 공식 문서에서 useInfiniteQuery 부분을 살펴보면서 정리해봅시다.
Infinite Queries | TanStack Query Docs
Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. TanStack Query supports a useful version of useQuery called useInfiniteQuery for querying these types of lists. When us
tanstack.com
Infinite Queires
기존 데이터에 더해 데이터를 더 불러와서 렌더링 하는 것이나 무한 스크롤은 매우 흔한 UI 패턴입니다. Tanstack Query는 이런 리스트형 데이터를 요청하기 위해, useQuery의 유용한 버전인 useInifiniteQuery를 지원합니다.
useInifiniteQuery
- data : inifinite query 데이터가 담겨있는 객체
- data.pages : fetch한 페이지들이 담겨있는 배열
- data.pageParams : 페이지들을 fetch 하는 데에 필요한 page params가 담겨있는 배열
- fetchNextPage와 getPreviousPageParam 옵션은 불러올 데이터가 더 있는지 여부와 fetch할 정보를 결정할 때 사용
- getNextPageParam함수가 undefined가 아닌 다른 값을 반환하면 hasNextPage는 true
- isFetchingNextPage와 isFetchPreviousPage로 백그라운드 새로고침 상태인지 추가 로딩 중인 상태인지 구별
본 프로젝트에서 무한 스크롤링은 다음과 같이 작동되게 됩니다.
- 우선 1페이지 데이터를 화면에 보여준다
- 더보기 버튼을 누르면 그 이후 페이지부터는 무한 스크롤 기능이 붙는다
- 마지막 페이지까지 보여주면 더 이상 무한 스크롤이 작동되지 않는다
해당 부분은 제가 구현하지 않아서 저는 제가 임의로 받아온 데이터들을 카드형식으로, 더보기를 위한 버튼을 만들어 구현해보았습니다.
🚀 구현해보자
1. 데이터를 fetch하는 함수를 선언해두자
const getList = async page => {
const res = await axios.get(`https://api.themoviedb.org/3/movie/popular`, {
params: { page, api_key },
});
return res.data.results;
};
위 getList 함수는 함수를 호출할 때마다 page라는 파라미터를 전달해주면 해당 페이지 데이터를 불러와 리턴하는 함수입니다. 해당 함수는 무한 스크롤링할 때마다 호출하여 데이터를 계속 받아올 때 사용될 함수입니다.
2. useInfiniteQuery 훅 함수 사용해서 필요한 걸 꺼내놓자
우선 무한 스크롤링 기능 구현을 위해 useInifiniteQuery를 통해 기본적으로 필요한 것들은 다음과 같습니다.
- data : 우리가 필요한 데이터가 담겨있는 객체
- hasNextPage : 다음 페이지가 있는지 → 다음 페이지가 없다면 더이상 데이터를 불러올 필요 X
- fetchNextPage : 다음 페이지 데이터를 불러와서 이전 데이터와 결합
- isFetchingNextPage : 다음 페이지를 불러오고 있는 중인지
- isLoading : 데이터를 불러오고 있는 중인지
const { data, hasNextPage, fetchNextPage, isFetchingNextPage, isLoading } =
useInfiniteQuery(
['infinity_popular_list'],
({ pageParam = 1 }) => getList(pageParam),
{
getNextPageParam: allPage => {
// allPages : 무한 스크롤링 하면서 누적하고 있는 데이터 리스트 [Array(20), Array(20) , ...]
const nextPage = allPages.length + 1;
return nextPage;
}
}
)
위 코드를 살펴보면, pagePage = 1을 기본으로 getList()에 전달하여 1페이지 데이터를 우선 불러옵니다. 그리고 fetNextPage() 함수가 호출되면 getNextPageParam에서 페이지별로 리스트로 묶여있는 리스트 즉, 불러온 페이지만큼의 길이를 가지고 있는 allPage 다음 페이지를 nextPage로 하여 리턴하여 그 다음 페이지 데이터를 fetch하게 됩니다.
3. 일정 스크롤이 감지될 때마다 데이터를 fetch 해야 한다
const [infinite, setInfinite] = useState(false);
useEffect(() => {
let fetching = false;
const onScroll = async e => {
const { scrollHeight, scrollTop, clientHeight } = e.target.scrollingElement;
if(!fetching && scrollHeight - scrollTop <= clientHeight * 1.2) {
fetching = true;
if(hasNextPage) await fetchNextPage();
fetching = false;
}
};
if(infinite) document.addEventListener('scroll', onScroll);
return () => document.removeEventListener('scroll', onScroll);
}, [fetchNextPage, hasNextPage, infinite]);
4. 이제 준비는 다 끝났다. 더보기 버튼을 누르면 무한 스크롤을 하도록 하고, 그 데이터를 화면에 뿌리자
return (
<div>
<S.Wrapper>
<ul>
{data?.pages.map(page =>
page.map(movie => (
<li key={movie.id}>
<div>{movie.title}</div>
<div>{movie.overview}</div>
</li>
))
)}
</ul>
</S.Wrapper>
{hasNextPage ? (
<S.Button
onClick={() => {
setInfinite(true);
fetchNextPage();
}}
>
더보기
</S.Button>
) : (
<div>더이상 없습니다!</div>
)}
<div>{isLoading && !isFetchingNextPage && '로딩중..'}</div>
</div>
);

'코드 회고 > 영화 목록 조회 프로젝트' 카테고리의 다른 글
[영화 목록 조회 프로젝트] React-Query로 검색 기능 구현 (0) | 2023.03.28 |
---|---|
[영화 목록 조회 프로젝트] 영화 목록 조회 프로젝트를 회고하기 전에 (0) | 2023.03.28 |
- Total
- Today
- Yesterday
- styled-components
- rtl
- 스타일 컴포넌트 styled-components
- 자바스크립트 기초
- 머신러닝
- 디프만
- frontend
- react
- 자바
- testing
- 타입스크립트
- HTML
- 프론트엔드 기초
- 딥러닝
- 프론트엔드 공부
- 프로젝트 회고
- TypeScript
- 프론트엔드
- 리액트 훅
- 데이터분석
- 리액트
- 자바스크립트
- CSS
- 인프런
- JSP
- 파이썬
- react-query
- jest
- next.js
- Python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |