
이전 글에서 react-query에 대해 장점을 설명 할 때 useInfiniteQuery에 대해 언급하였고 간단하게 채팅을 만들때도 사용했다. useInfiniteQuery와 intersection-observer의 useInView를 사용해 간단하게 infinity scroll을 구현하는 글을 기록하기로 했다.
기존에 infinity scroll을 구현하기위해 scroll 이벤트감지, redux-saga, infinity scroll라이브러리, hook만들어서 사용하기 등 구현 할 수있는 방법은 거의 다 해보았다. 그 결과 intersection-observer의 useInView와 react-query의 useInfiniteQuery를 사용 했을때 가장 깔끔하고 좋았다.

글 목록에서 세부내용으로 화면이 바뀐후 돌아왔을때 스크롤 위치가 초기화 되지 않는다
import React, { useEffect } from "react";
import { useInfiniteQuery } from "react-query";
import { useInView } from "react-intersection-observer";
import { Link } from "react-router-dom";
import axios from "axios";
const ScrollTest = () => {
const { ref, inView } = useInView(); // ref가 화면에 나타나면 true 또는 false를 반환한다.
const { isLoading, isError, error, data, fetchNextPage, isFetching, isFetchingNextPage, refetch, hasNextPage } = useInfiniteQuery(
"chat_list",
async ({ pageParam = 1 }) => {
const { data } = await axios.get(`api&page=${pageParam}`);
return data;
},
{
onSuccess: (data) => {// 성공시 호출},
refetchOnWindowFocus: false,
staleTime: Infinity,
cacheTime: Infinity,
getNextPageParam: (lastPage) => {
return lastPage.page === 3 ? false : lastPage.page + 1; //테스트용으로 3페이지로 페이지 제한 실제로 사용할때는 api에서 내려오는 값을 이용해야함
},
}
);
useEffect(() => {
if (inView) {
fetchNextPage();
}
}, [inView]);
//viewport에 Load More 버튼이 보여지게 되면 true를 반환하고 useEffect에서 fetchNextPage();를 실행해 다음페이지를 불러오게 된다.
return (
<>
{data?.pages.map((page) =>
page.result.map((item) => (
<div className="div_box" key={item.id}>
<Link to={`/test/detail/${item.id}`}>{item.id}</Link>
</div>
))
)}
<div>
{!hasNextPage || isFetchingNextPage ? (
<div>더 이상 표시할 데이터 없음</div>
) : (
<button onClick={fetchNextPage} disabled={!hasNextPage || isFetchingNextPage} ref={ref}>
Load More
</button>
)}
</div>
</>
);
};
export default ScrollTest;