안녕하세요. 최근에 이직을 하게 되면서 react-query를 접할 일이 생겼는데 기존에 사용하던 SWR과 비슷하여 그중에서 useInfiniteQuery
의 공식 홈페이지 예제를 보자마자 🤮PTSD가 왔습니다.
useSWRInfinite
만큼은 아니었지만 인피니티 스크롤 기능 하나 때문에 예제처럼 많은 코드를 쓰기는 싫었기 때문에 모듈화를 하여 개선해 보려고 합니다.
결론부터 말씀드리자면 react-query-infinite-scroll 을 사용하시면 됩니다.
그렇습니다. 사실 라이브러리를 흥보 하고 싶었습니다.😁
어떻게 개선되는지 보겠습니다.
// IO Custom Hooks
const useOnScreen = (ref, rootMargin = "0px") => {
// State and setter for storing whether element is visible
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
// Update our state when observer callback fires
setIntersecting(entry.isIntersecting);
},
{
rootMargin,
}
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.unobserve(ref.current);
};
}, []); // Empty array ensures that effect is only run on mount and unmount
return isIntersecting;
}
// Example
import { useInfiniteQuery } from '@tanstack/react-query'
function Projects() {
const fetchProjects = async ({ pageParam = 0 }) => {
const res = await fetch('/api/projects?cursor=' + pageParam)
return res.json()
}
const {
data,
error,
fetchNextPage,
hasNextPage,
status,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})
const ref = useRef()
const isIntersecting = useOnScreen(ref);
useEffect(()=>{
if(isIntersecting){
fetchNextPage()
}
},[isIntersecting])
if(status === 'loading'){
return <p>Loading...</p>
}
if(status === 'error'){
return <p>Error: {error.message}</p>
}
return (
<>
{data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div ref={ref}></div>
</>
)
}
yarn add react-query-infinite-scroll
npm i react-query-infinite-scroll
pnpm i react-query-infinite-scroll
설치 부터 해줍시다
import { useInfiniteQuery } from "@tanstack/react-query";
import { QueryInfiniteScroll } from "react-query-infinite-scroll";
const fetchProjects = async ({ pageParam = 0 }) => {
const res = await fetch('/api/projects?cursor=' + pageParam)
return res.json()
}
const query = useInfiniteQuery<TValue>(
["list"],
fetchProjects,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
);
<QueryInfiniteScroll<TValue>
query={query}
loading={<div>loading</div>}
error={<div>error</div> || (error)=> <div>{error}</div>}
observer={<div>loading</div>}
>
{(res) => {
return res?.data.map((data, idx) => <div key={idx}>{data._id}</div>);
}}
</QueryInfiniteScroll>
data fetch
중 로드 중인 경우 대체할 컴포넌트를 넣어주시면 되겠습니다data fetch
가 로드 중 실패 한 경우 대체할 컴포넌트를 넣어주시면 되겠습니다react-query v3 도 v4와 동일한 반환값을 가지고 있기 때문에 동일하게 사용 가능합니다
제발🙏 사용해주시면 감사하겠습니다...
끝입니닷
좋은 글 감사합니다! 무한스크롤 구현할 때 꼭 사용해봐야겠네요