무한 스크롤은 동작하지만 가장 마지막 데이터에 스크롤이 교차됐을때 컴포넌트가 계속해서 리렌더링됨. 콘솔 테스트 문자열을 각각 추가해봤는데 정확히는 가장 마지막 데이터가 로딩된 이후에 계속해서 서버에서 데이터를 받아오는 함수가 실행되어 콘솔에 테스트 문자열이 무한으로 출력된다.
useEffect(() => {
getAllPosts();
}, [page]);
일차적으로 이 코드로 인해서 page 값에 따라 getAllPosts 함수가 실행이 됨 이 함수는 서버와 통신해서 전체 게시글을 받는 함수다.
page 값은 옵저버 객체의 콜백함수에서 증가시키고 있는데 아래와 같다.
// 옵저버 객체 생성
useEffect(() => {
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && entries[0].intersectionRatio >= 1) {
setPage((prevPage) => prevPage + 1);
}
},
{ threshold: 1 }
);
if (lastPostRef.current) {
// 데이터가 불러와지기 전에 실행하면 안되니까 lastPostRef.current가 있을때로 조건 생성
observer.current.observe(lastPostRef.current);
}
}, [allPosts]);
관찰 중일때 page 값이 1 올라가게 작성되어있다.
이런 흐름으로 무한 함수 호출이 된거 같은데
getAllPosts
호출로 게시글 불러옴 getAllPosts
실행됨getAllPosts
실행 == 서버랑 통신해서 데이터 받아옴 서버랑 통신하는 함수에서 더 줄 데이터가 없을 때(response.data의 length가 size 보다 작을 때) 콘솔에 page
와 더 이상 가져올 데이터 없음
을 추가했더니 아래와 같이 무한 page 값 증가와 함께 콘솔이 무한으로 찍힌다 ㅎㅎ
더 이상 받아올 데이터가 없을 때는 서버와 통신을 멈추면 된다!
라는 개념을 가지고 이 문제를 해결했다.
// 더 이상 불러올 데이터가 있는지 표시하는 상태
const [hasMore, setHasMore] = useState(true);
서버와 통신하는 함수인 mutateAllPosts 에서 아래와 같이 조건을 생성해줌
// 전체 게시글 조회 뮤테이션 함수
const { mutate: mutateAllPosts } = useMutation(fetchAllPosts, {
onSuccess: (response) => {
if (response.statusCode === 200) {
setAllPosts((prevPosts) => [...prevPosts, ...response.data]);
// 더 이상 가져올 데이터 없음
if (response.data.length < size) {
setHasMore(false);
}
}
},
onError: (error) => {
console.log(error);
},
});
그러니까 서버에서 받아온 데이터가 내가 정한 size(서버에 통신할 때 데이터를 몇 개 받아올지 지정하는 파람값) 개수보다 적으면 더 이상 받아올 데이터가 없다고 판단-> hasMore 값을 false로 변경해준다.
mutateAllPosts를 실행시키는 함수에서 통신을 더 할지 말지를 결정하는 hasMore 값이 false일때는 더 이상 mutateAllPosts 함수를 실행시키지 않는 조건을 추가한다.
// 전체 게시글 불러오기
const getAllPosts = () => {
// 더 이상 불러올 데이터가 없다면 종료
if (!hasMore) return;
mutateAllPosts({ page, size });
};
위와 같이 가장 마지막 데이터에 스크롤이 교차했을 때, 한 번의 콘솔만 출력되고 더 이상 서버에 데이터를 요청하는 함수가 실행되지 않는다! ㅎㅎ
서버에서 받아온 데이터가 더 이상 없을 때 요청을 멈추는 추가 로직을 생각하지 못해서 생긴 에러인 것 같다!