프로젝트를 진행하면서 막연히 리액트쿼리를 사용해보자! 하고 기본적인건 사용해봤는데 무한스크롤을 구현해보려고 찾아보니 리액트쿼리에 있는 useInfiniteQuery를 사용해서 무한스크롤을 구현할 수 있다는걸 알게되었다.
사용해볼수록 찾아볼수록 유용한 기능은 많은 거 같아서 재밌다!
useInfiniteQuery
리액트쿼리에서 useInfiniteQuery Hook은 인피니트 스크롤링과 같은 페이징된 데이터를 처리할 때 사용된다. 사용 방법은 useQuery와 비슷하고 주어진 쿼리를 실행하여 페이징된 데이터를 가져온다.
기본 설정하기
const { data, status, error, fetchNextPage, isFetchingNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
// 초기 페이지 매개변수
initialPageParam: 1,
// 다음 페이지의 페이지 매개변수를 결정하는 함수
getNextPageParam: (lastPage, allPages) => {
// 마지막 페이지 이후의 불필요한 통신을 막기위함
const nextPage = lastPage.length ? allPages.length + 1 : undefined;
return nextPage;
},
});
- data : 쿼리에서 반환된 데이터
- status : 쿼리의 상태 (loading, success, error)
- error : 쿼리 실행 중 발생한 오류
- fetchNextPage : 다음 페이지를 가져오는 함수, 이 함수를 호출하면 새로운 페이지의 데이터를 가져옴
- isFetchingNextPage : 다음 페이지를 가져오는 중인지 여부를 나타내는 변수
- hasNextPage : 다음 페이지가 있는지 여부를 나타내는 변수
무한스크롤을 구현하기 위해서는 useInfiniteQuery만 사용할 뿐만 아니라 사용자가 스크롤 페이지 끝에 도달할 때 감지할 수 있는 라이브러리를 설치합니다.
설치하기
npm i react-intersection-observer
사용하기
const { ref, inView } = useInView();
...
useEffect(() => {
if (inView && hasNextPage) {
console.log("Fire!");
fetchNextPage();
}
}, [inView, hasNextPage, fetchNextPage]);
...
- useInView : 스크롤 이벤트 관찰하는 hook
- inView : 화면에 현재 요소가 보이는지 여부를 나타내는 값
- ref : 마지막 아이템을 관찰하는 요소
최종코드
import { useEffect, useState } from "react";
import "./App.css";
import TodoCard from "./components/TodoCard";
import { todo } from "./types/todo";
import { useInfiniteQuery } from "@tanstack/react-query";
import { useInView } from "react-intersection-observer";
function App() {
const { ref, inView } = useInView();
const fetchTodos = async ({ pageParam }: { pageParam: number }) => {
const res = await fetch(`https://jsonplaceholder.typicode.com/todos?_page=${pageParam}`);
return res.json();
};
const { data, status, error, fetchNextPage, isFetchingNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
initialPageParam: 1,
getNextPageParam: (lastPage, allPages) => {
const nextPage = lastPage.length ? allPages.length + 1 : undefined;
return nextPage;
},
});
useEffect(() => {
if (inView && hasNextPage) {
console.log("Fire!");
fetchNextPage();
}
}, [inView, hasNextPage, fetchNextPage]);
if (status === "pending") {
return <p>Loading...</p>;
}
if (status === "error") {
return <p>Error: {error.message}</p>;
}
return (
<div className="app">
{data?.pages.map((todos: todo[]) =>
todos.map((todo, index) => {
if (todos.length == index + 1) {
return <TodoCard innerRef={ref} key={todo.id} todo={todo} />;
}
return <TodoCard key={todo.id} todo={todo} />;
}),
)}
{isFetchingNextPage && <h3>Loading...</h3>}
</div>
);
}
export default App;
📌
How to Create Infinite Scroll in React | TanStack React Query
'Front-end > React' 카테고리의 다른 글
[React] 상태관리 라이브러리 - Redux toolkit(RTK) (0) | 2024.05.01 |
---|---|
[React] react-date-range 라이브러리로 캘린더 만들기 (feat.date-fns) (0) | 2024.04.11 |
[React] 리액트쿼리(React Query)란? (0) | 2024.03.25 |
[React] react Swiper로 슬라이드 기능 구현하기 - 버튼 커스텀, breakpoints (0) | 2024.03.20 |
[React] 모달창 구현 - 라이브러리 없이 구현하기 vs Chakra UI 사용하기 (0) | 2024.03.12 |