요즘 서비스에서는 페이징 기법으로 페이지를 이동하는것보다, 페이지를 내려 새로운 리소스를 가져오는 무한스크롤 기반의 페이지가 많다. UX쪽 측면으로 1페이지, 2페이지 이동하는 것보다 하단으로 스크롤을 내려 페이지를 이동하는것이 편하기 때문이다. 또한 모든 데이터를 로드하면 랜더링이 느려지기 때문에 부분부분 필요한 데이터를 호출해야한다.
프로젝트에 무한스크롤을 적용하려고 한다. 무한스크롤에서 특정 위치에서 데이터를 로드하기 위해 useInView 훅을 사용하려고 한다. useInView 훅은 컴포넌트의 inView 상태를 모니터링해주는 훅이다. 요소가 뷰포트에 진입/제외 되는 시점을 파악시켜준다. (react-intersection-observer)
다음 무한페이징을 구현하기위해 useInfiniteQuery 훅을 사용했다. useInfiniteQuery훅은 페이징된 데이터를 관리하고 캐싱하기 위해 사용된다. REST API를 통해 데이터를 비동기적으로 가져와 쿼리 결과를 관리하는 데 효과적이다.
다음은 InfiniteQuery의 문서이다. (useInfiniteQuery)
data: 쿼리로부터 받은 데이터
status: 쿼리 상태를 나타냄. loading", "error " "success" 가 있음.
fetchNextPage: 다음 페이지를 가져오는 함수
hasNextPage: 가져올 다음 페이지가 있는지 알려주는 불리언 값
isFetchingNextPage: 다음 페이지를 가져오는 동안 true인 불리언 값.
const [ref,inView] = useInView();
const { data, status, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery("products", ({ pageParam = 0 }) => getProduct(pageParam), {
select: data => ({
pages: data.pages,
nextPage: data.pages.length+1,
pageParam: data.pageParams,
}),
getNextPageParam: (lastPage, allPages) => {
const nextPage = allPages.length;
return lastPage.nextPage === 0 ? undefined : nextPage;},
});
async function getProduct(page) {
const res = await axios.get(`http://localhost:8081/product/main?page=${page}`);
const result = res.data;
console.log(result)
return {
result: result.content,
isLast: res.data.last
};
}
useEffect(() => {
if (inView && hasNextPage) {
fetchNextPage({
page: data.nextPage,
});
}
}, [inView, hasNextPage]);
return (
<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "16px" }}>
{data ? (
data.pages.map((item) =>
item.result.map((list, idx) =>
<Card lastItemRef={idx === item.result.length - 1 ? ref : null} index={idx} data={list} />
)
)
) : (
<div>Loading...</div>
)}
</div>
);
useInView 훅을 사용하여 뷰포트 내에서 요소가 보이면 fetchNextPage 함수를 호출하여 다음 페이지를 가져오도록 했다.
무한스크롤을 구현한 화면이다.
inView가 true이고 hasNextPage가 true일 때 데이터를 가져오는 요청을 보낸다.
더이상 가져올 데이터가 없으면 isLast가 True이기 때문에 다음페이지를 호출하지 않는다.
구현코드
https://github.com/ungyuun/Clozet/blob/master/src/main/client/src/pages/product/main/Main.jsx
참고사이트
'Clozet [프로젝트]' 카테고리의 다른 글
[nginx] 리액트 + 스프링부트 프로젝트 배포 (0) | 2023.11.18 |
---|---|
[Clozet] 지도 검색 범위 지정하기 (0) | 2023.11.11 |
[프로젝트] 물품 장바구니,구매 예외처리하기 (0) | 2023.10.29 |
[Project] Clozet 프로젝트 시작 (0) | 2023.09.23 |