Infinity Scroll 리스트 아이템 데이터 수정 안되는 문제(Feat. useInfiniteQuery, fetchNextPage, hasNextPage)

박민형·2023년 7월 22일
0
post-thumbnail

독서 모임 조회페이지를 무한 스크롤로 구현한 상태였다. 독서 모임 수정 페이지를 작업하다 독서 모임 조회페이지에서 마지막 아이템이 render 되는 위치(스크롤 최하단)의 아이템들은 수정이 되지 않는 문제를 발견했다. 어떤 문제가 발생했고 그 문제를 어떻게 해결하였는지 포스팅 해보려고 한다!

📌 문제를 해결해야 했던 이유

  • 사용자가 독서 모임 정보를 수정했을 때 독서 모임 조회페이지에 여전히 이전 데이터가 render 되는 것은 크리티컬한 문제라고 판단
  • 해당 문제로 인해 데이터가 즉각적으로 업데이트가 되지 않는다면 UX에 치명적일 것이라는 판단을 해 작업을 진행했다.

📌 문제 상황

  • 마지막 아이템이 render 되는 위치(스크롤 최하단)에서 보이는 독서 모임 리스트 아이템을 수정 후 독서 모임 조회페이지 돌아왔을 때 수정한 데이터 반영 안됨

  • 독서의 왕도 수정 이라고 모임 이름을 수정 했지만 업데이트 되지 않고 있다...

🔎 스크롤이 최하단이 아닐때 보이는 리스트 아이템은?

  • 스크롤이 최하단이 아닐 때 보이는 리스트 아이템 같은 경우 수정 작업 후 독서 모임 조회페이지 돌아왔을 때 수정된 데이터가 업데이트 되었다!

📌 문제 해결 과정 1 - 서버로부터 응답받은 데이터 check

  • 수정된 데이터를 정상적으로 fetch 하지 못해서 그런가? 라는 1차적인 생각이 들었다.
  • network Tab(첫번째 사진), api 데이터 응답 받는 부분 console 출력(두번째 사진)한 결과 수정된 데이터를 정상적으로 fetch하고 있었다.

  • 하지만, 무한 스크롤 컴포넌트에서 리스트 데이터를 console 출력한 결과 이전 데이터가 render 되는 상황이였다...

📌 문제 해결 과정 2 - inview check

🔎 inview가 뭔가요?

  • viewport에서 특정 요소(주로 위치를 하단에 설정)가 관찰되면 다음 데이터를 render하는 것이 무한 스크롤의 기본 원리다.
  • 그러기 위해서는 특정 요소를 비동기로 관찰하고 있어야만 한다.
  • 우리팀은 react-intersection-observer 라이브러리 도입 및 useInView Hook을 사용해 특정 요소 관찰 작업을 처리하기로 했다.
  • useInview 구성 요소
    • ref : 관찰해야하는 요소의 ref props 값으로 설정하면 해당 요소는 관찰 대상이 된다.
    • inView : viewport에서 등록한 요소가 관찰되면 true, 관찰되지 않으면 false를 반환하는 boolean 값
  import { useInView } from 'react-intersection-observer';
  
  const { ref, inView } = useInView();
  
  // Bottom 컴포넌트가 viewport에서 관찰되면 다음 데이터를 fetch
  useEffect(() => {
    if (inView) fetchNextPage();
  }, [fetchNextPage, inView]);
  
  // Bottom 컴포넌트를 관찰대상으로
  <Bottom ref={ref}>
    {isFetchingNextPage && hasNextPage && 'Loading...'}
  </Bottom>

👉 이제 문제 해결하로 가시죠!

  • 데이터 fetch 자체에 문제가 있는 것이 아니라 최하단에서만 해당 문제가 발생하니까 inView에 문제가 있지 않을까라는 생각을했다. 그 생각에 착안해 스크롤이 최하단일 때와 그 이외의 상황일 때 useEffect 안에서 콘솔을 찍어보았다.
  • 소스코드
  useEffect(() => {
    if (inView) {
      console.log('next page');
      fetchNextPage();
    }
  }, [fetchNextPage, inView]);
  • 첫번째 사진은 독서 모임 수정 후 조회페이지에 돌아왔을 때 스크롤이 최하단일 때 콘솔을 출력한 결과이다. 최하단이다 보니 inView가 true이고 그에따라 next page 문자 출력 및 fetchNextPage()를 호출한다.
  • 두번째 사진은 스크롤이 최하단이 아닐 때 콘솔을 출력한 결과로서 inView가 false다 보니 아무런 task를 수행하지 않는다.

📌 문제 해결

  • 위의 결과를 바탕으로 최하단일 때도 fetchNextPage가 호출되지 않도록 함으로써(hasNextPage 사용) 문제를 해결할 수 있었다.
  useEffect(() => {
    if (!inView) return;

    // fetch할 다음 데이터가 있을때만 fetchNextPage() 호출
    // 마지막 아이템 같은 경우 hasNextPage가 false 이므로 fetchNextPage() 호출 x
    hasNextPage && fetchNextPage();
  }, [fetchNextPage, inView, hasNextPage]);
  • 마지막 아이템이 render 되는 위치(스크롤 최하단)의 리스트 아이템도 수정된 데이터가 정상적으로 반영되는 것을 확인할 수 있다.

📌 fetchNextPage가 호출 되면 수정 된 데이터를 render 하지 못하는 이유(추측)

  • 결론부터 말하면 최신 데이터를 반영하지 못하는 이유는 fetchNextPage 호출이지만 구체적인 이유와 enabled에 의한 query 활성화와의 인과관계를 정확히 파악하지는 못했다.
  • 단지 fetchNextPage가 호출됨으로 인해 왜 수정된 데이터를 render 하지 못하는지 이해하기 어려웠다. enabled에 의해 query가 다시 활성화 되고 있는 상황이였기 때문이였다.
  • fetchNextPage에 대한 개념을 찾아봤지만 다음 페이지가 있을 경우 다음 페이지 데이터를 가져온다는 설명밖에 없었다.
  • 모든 상황에서 해당 개념이 동일하게 동작하지 않는다는 생각을 바탕으로 현재 상황을 분석해보았다 => query에 이전 데이터가 캐싱되어 있고 가져올 다음 페이지가 없을 때(마지막 아이템, 스크롤 최하단) 컴포넌트가 마운트 된 후 fetchNextPage()가 수행 => enabled에 의해 쿼리 활성화
  • 위의 상황에서 발생되는 현상과 관련해 chat GPT에게 물어봤고 이와 같은 답변을 해주었다.
    • 위의 상황에서 fetchNextPage()가 수행가 수행되는 경우 => 이미 존재하는 데이터를 활용하여 컴포넌트가 렌더링됩니다. 하지만 실제로 새로운 데이터가 없으므로 화면에 변경된 내용은 없을 수 있습니다.
    • fetchNextPage와 enabled에 의한 쿼리 활성화가 동시에 발생하면 데이터 중복현상이 발생할 수 있음
  • 즉, fetchNextPage와 쿼리 활성화 동작이 동시에 일어나다보니 최신데이터를 render 하지 못한다고 추측할 수 있을 것 같다.

📌 결론

  • 각 개념이 각자 역할을 하는 것에 있어서는 문제가 없었지만 각 개념의 중복으로 인한 Error 및 인과관계를 파악하는 것이 쉽지는 않았다. 다음부터는 현재 적용하고 있는 개념이 다른곳에도 영향을 줄수 있다는 것을 인지한 후에 작업할 수 있도록 해야겠다!

0개의 댓글