본문 바로가기
JavaScript/리액트 React

react-query) staleTime 과 gcTime, 그리고 InfiniteQuery

by 하이방가루 2024. 5. 16.
728x90
반응형

useInfiniteQuery를 사용하여 무한 스크롤을 구현하던 중 문제가 발생했다.

새로운 데이터를 넣고 invalidateQueries 메서드로 해당 키의 데이터를 stale 상태로 바꾸고,

무한 스크롤로 구현한 조회 페이지의 들어갔을 때,

네트워크 요청이 내가 스크롤해서 불러온 요청한 수만큼 한 번에 서버에 요청이 들어간 것이다.

 

예) 조회 페이지에서 스크롤링하여 4번 데이터 불러옴. -> 데이터 등록 페이지에서 새로운 데이터 추가 -> 조회 페이지로 이동 -> 한 번에 4번 요청.

 

현재 우리 페이지는 최신순으로 데이터를 정렬하므로

새로운 데이터가 제대로 들어갔는지 확인만 하려고 하는 것이라면 굳이 스크롤하지 않을 것이기 때문에

최상단의 데이터 1번만 요청하면 되는데, 그동안 보았던 페이지만큼 다시 fetch를 실행하는 것이었다.

 

왜 이런 일이 발생했을까?

 

먼저 useInfiniteQuery를 사용했을 때 일반적으로 useQuery를 사용했을 때 queryKey 하나에 저장되는 데이터의 구조를 비교해보자.

useQuery를 사용했을 때
useInfiniteQuery를 사용했을 때

 

일반적으로 useQuery를 사용했을 때에는 데이터가 그대로 저장이 되는 반면,

useInfiniteQuery를 사용했을 때는 pageParams라는 키에 페이지 번호를 저장하고, pages 키에 각 페이지에 해당하는 데이터들을 저장해 놓았다.

 

해당 queryKey가 stale 상태가 되었을 때 fresh 한 데이터를 가져오기 위해서

useQuery를 사용하여 가져온 데이터는 한 번만 fetch를 진행하는 반면에,

useInfiniteQuery를 사용했을 때는 pageParams와 pages 모두 fresh 한 데이터로 만들기 위해서 페이지 수 만큼 fetch를 진행하게 되는 것이다.

 

따라서 이를 해결하기 위해서는 데이터를 지워줄 필요가 있다.

 

먼저 데이터 변경이 없는 상태에서 stale한 데이터를 지우려고 할 경우,

간단히 staleTime과 gcTime을 동일하게 설정하면 된다.

이렇게 하면 stale한 데이터가 되었을 때 react-query gabage collector에 의해서 데이터가 정리된다.

 

다음은 데이터를 수정하여 fetch가 필요할 때이다.

이 경우는 우리가 직접 데이터를 비워줄 필요가 있다.

바로 queryClient.setQueriesData(filters, updater) 메서드를 이용하면 된다.

 

주의)

queryClient.setQueryData(queryKey, updater) 는 queryKey가 완벽하게 일치하는 하나의 데이터만을 수정하기 때문에 검색이 가능한 조회 페이지일 경우 queryClient.setQueriesData(filters, updater) 을 사용하여 검색 키워드에 해당하는 데이터들도 지워줘야 한다.

 

queryClient.setQueriesData(
    { queryKey: [mainKey, 'list'] },
    (oldData) => {
      return null;
    }
  );
await queryClient.invalidateQueries(mainKey);

 

이렇게 하면 해당 queryKey를 가지는 모든 데이터를 순회하여 데이터를 update 하고 stale 상태로 변경하여 최상단 데이터만을 fetch하게 된다.

 

주의)

undefined 를 return할 경우 데이터를 update 하지 않는다.

728x90
반응형

댓글