React Query 페이지 전환 시 캐싱하지 않는 에러

리오·2023년 5월 23일
1

Front End

목록 보기
5/10
post-thumbnail

회사의 레거시 코드에서 각 페이지마다 동일한 api 요청을 하는 부분이 많이 있었습니다. 이 요청에 대한 응답으로 오는 데이터는 사실상 거의 변하지 않는 데이터였습니다.
업데이트가 거의 일어나지 않는 데이터를 모든 페이지에서 요청하는 것보다, 캐싱을 해두면 좋을 것 같다는 생각에 react query를 적용해보기로 했습니다.
그런데 페이지 전환 시에 fresh 상태인 데이터를 사용하지 않고, 새로 데이터를 요청해서 데이터가 리페치되는 문제가 있었습니다.

결론부터 말하자면 queryClient 선언을 App 컴포넌트 내부에서 했기 때문에 발생한 문제였습니다.

문제 발견

react-query-devtools에서 확인해보니 제가 작성한 코드에서 React Query가 예상과 다르게 동작하는 문제는 다음 두 가지였습니다.

1. URL 경로가 변경되거나, 페이지를 이동했을 때 기존에 캐싱된 데이터가 있음에도 불구하고 새롭게 요청을 보내서 리페칭하고 있음.

2. 새로고침이 되고 데이터 요청이 일어났을 때, 응답으로 온 데이터가 잠깐 캐싱되었다가 사라짐.

첫 번째 문제의 경우, 개발자 도구-네트워크 탭에서 캐싱을 이미 했던 데이터임에도 불구하고 재요청하는 것을 확인해서 발견하였습니다.

두 번째 문제는 ReactQuery Devtools에서 발견하였습니다. 캐싱된 데이터의 경우, 해당 키 값과 캐싱된 데이터가 표시되어야 하는데, 새로고침을 한 경우 마치 깜빡이듯이 데이터가 잠깐 나타났다가 다시 사라지고 있었습니다.

옵션 값

검색을 통해 알게 된 내용에 따르면, 많은 사람들이 React Query 옵션 값(특히 staleTime)을 변경해야 한다고 언급했습니다.

저는 이미 Query Client를 선언할 때 defaultOptions를 통해 옵션 값을 설정했습니다. (reactQueryOption.js 파일 참고)

  //reactQueryOption.js
  export const reactQueryOption = {
  queries: {
    retry: 0, // 실패한 쿼리의 재시도 횟수. 0이면 재시도하지 않음.
    suspense: true, // Suspense 컴포넌트를 사용하여 쿼리 로딩 상태를 처리할지 여부를 나타내는 플래그.
    staleTime: 60 * 1000, // 데이터가 stale 상태로 간주되기 전까지의 시간(밀리초). 이 시간 동안은 캐시된 데이터를 사용하고, 네트워크 리퀘스트를 보내지 않음.
    cacheTime: 5 * 60 * 1000, // 데이터를 캐시하는 기간(밀리초). 이 기간 동안은 캐시된 데이터를 사용하고, 네트워크 리퀘스트를 보내지 않음.
    refetchOnMount: false, // 컴포넌트가 마운트될 때마다 쿼리를 리페치할지 여부를 나타내는 플래그.
    refetchOnWindowFocus: false, // 윈도우가 포커스를 받을 때마다 쿼리를 리페치할지 여부를 나타내는 플래그.
    refetchInterval: 60 * 1000, // 주기적으로 쿼리를 리페치하는 간격(밀리초).
  }
}

  //App.js
  function App() {
	...
    const queryClient = new QueryClient({
      defaultOptions: reactQueryOption,
    });
    ...
  }

staleTime에 대해서는 DevTools에서 표시된 데이터가 60초가 지난 후에 fresh 상태에서 stale 상태로 변경되는 것을 확인했습니다. 따라서 옵션이 적용되지 않거나 staleTime 값이 문제라고 판단하지 않았습니다.

해결 방법

queryClient 선언 코드를 App 컴포넌트 바깥으로 옮기면서 문제가 해결되었습니다.

위의 코드를 보시면 알겠지만 queryClient를 App 컴포넌트 내부에서 선언하였습니다.
이 경우 매번 App 컴포넌트가 렌더링될 때마다 새로운 queryClient 인스턴스가 생성됩니다. 따라서 각 페이지 컴포넌트가 독립된 쿼리 클라이언트 인스턴스를 사용하게 되어, 데이터가 정상적으로 캐싱되지 않았던 문제였습니다.
또한 새로고침 시에도 새로운 queryClient 인스턴스가 생성되기 때문에, devtools에서도 정상적으로 표시가 되지 않았던 것이었습니다.
따라서 queryClient 선언부를 다음과 같이 수정하였습니다.

  //App.js
   const queryClient = new QueryClient({
      defaultOptions: reactQueryOption,
    });
    
  function App() {
	...
  }

queryClient 선언 코드를 App 컴포넌트 바깥으로 옮긴 후에 문제가 정상적으로 해결되었습니다.

마치며

이전에 React Query를 몇 번 사용해 본적이 있었습니다. 때문에 익숙하다는 이유로, 공식문서를 제대로 읽어보지 않았던 것 같습니다. 어떤 기술을 도입할 때, 해당 기술의 공식문서를 꼼꼼히 읽어보는 습관을 가져야 할 것 같습니다.

profile
오늘도 승승장구를 위해 연습 중

0개의 댓글