무한 스크롤 에러 : 더 이상 받아올 데이터가 없는데도 서버와 무한 통신

soo's·2023년 6월 7일
0

에러  정리

목록 보기
8/10

0. 문제상황

무한 스크롤은 동작하지만 가장 마지막 데이터에 스크롤이 교차됐을때 컴포넌트가 계속해서 리렌더링됨. 콘솔 테스트 문자열을 각각 추가해봤는데 정확히는 가장 마지막 데이터가 로딩된 이후에 계속해서 서버에서 데이터를 받아오는 함수가 실행되어 콘솔에 테스트 문자열이 무한으로 출력된다.

1. 문제인식

  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 올라가게 작성되어있다.
이런 흐름으로 무한 함수 호출이 된거 같은데

  1. 컴포넌트 렌더링시 getAllPosts 호출로 게시글 불러옴
  2. 불러온 데이터의 가장 마지막 데이터(디비의 마지막 데이터가 아니라 size 파람을 기준으로 잘라서 가져온 데이터들 중 마지막)에 있는 ref를 기준으로 관찰을 시작
  3. 대상이 관찰되면(뷰표트에 잡히면) 콜백함수 실행 = page 값 1 증가
  4. page 값 변경으로 인하여 getAllPosts 실행됨
  5. getAllPosts 실행 == 서버랑 통신해서 데이터 받아옴
  6. 이 과정을 반복하다가 서버 db의 마지막 데이터까지 줬을때 끝나지 않고 또 모든 과정을 반복 반복 반복...

서버랑 통신하는 함수에서 더 줄 데이터가 없을 때(response.data의 length가 size 보다 작을 때) 콘솔에 page더 이상 가져올 데이터 없음을 추가했더니 아래와 같이 무한 page 값 증가와 함께 콘솔이 무한으로 찍힌다 ㅎㅎ

2. 문제 해결

더 이상 받아올 데이터가 없을 때는 서버와 통신을 멈추면 된다!
라는 개념을 가지고 이 문제를 해결했다.

1. 데이터를 더 받아올지에 대한 state 생성

  // 더 이상 불러올 데이터가 있는지 표시하는 상태
  const [hasMore, setHasMore] = useState(true);

2. 데이터 없을 때 조건 생성

서버와 통신하는 함수인 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로 변경해준다.

3. mutateAllPosts 실행시키는 함수에 조건 생성

mutateAllPosts를 실행시키는 함수에서 통신을 더 할지 말지를 결정하는 hasMore 값이 false일때는 더 이상 mutateAllPosts 함수를 실행시키지 않는 조건을 추가한다.

  // 전체 게시글 불러오기
  const getAllPosts = () => {
    // 더 이상 불러올 데이터가 없다면 종료
    if (!hasMore) return;
    mutateAllPosts({ page, size });
  };

해결


위와 같이 가장 마지막 데이터에 스크롤이 교차했을 때, 한 번의 콘솔만 출력되고 더 이상 서버에 데이터를 요청하는 함수가 실행되지 않는다! ㅎㅎ
서버에서 받아온 데이터가 더 이상 없을 때 요청을 멈추는 추가 로직을 생각하지 못해서 생긴 에러인 것 같다!

0개의 댓글