react-query는 전역 상태관리, 코드 간소화 등 많은 장점이 있지만 가장 매력적인 기능은 캐싱 기능이다. react-query 없이 서버의 데이터를 받아 클라이언트쪽에서 캐싱하는 기능을 어떻게 구현해야할지는 감히 상상도 안된다. 그러나 이 캐싱기능을 제대로 사용하기 위해 react-query의 stale, cachetime, refetch 등에 대한 사전 공부가 필요하다.
사전적 정의는 '탁한', '신선하지 않은'이라는 뜻이다. 가져온 데이터가 stale하다면, 이 데이터는 더 이상 신선하지 않는 것이기 때문에 업데이트가 필요하다. react-query는 쿼리가 stale 할때, 다음과 같은 상황에서 해당 쿼리를 refetch 한다.
(출처: https://react-query-v3.tanstack.com/guides/important-defaults)
각각의 refetch 되는 상황은 제공되는 옵션을 통해 사용여부를 수정할 수 있다.
1. 새로운 인스턴스가 마운트 될때 👉🏻 refetchOnMount
2. 브라우저 화면이 다시 focus 됐을 때 👉🏻 refetchOnWindowFocus
3. 네트워크가 재연결됐을 때 👉🏻 refetchOnReconnect
4. 특별히 설정한 refetch interval이 있을 때 👉🏻 refetchInterval
위와 같이 ["portfolio",유저이름] 형식의 query key, query function으로 getUserPortfolio 를 갖는 특정한 쿼리가 캐시되어있다고 하자. 그렇다면 이 선언이 포함된 컴포넌트가 다시 랜더 된다면 자동으로 캐시된 데이터를 사용하여 보여줄까?
그렇지 않다.
여기서 staleTime에 대한 지식이 필요하다. staleTime은 쿼리를 fetch한 이후에 데이터가 stale상태가 되는데까지 소요되는 시간을 말한다. react-query는 staleTime을 디폴트로 0으로 설정했다. 즉, 위와 같이 useQuery를 선언하고 별도의 옵션을 설정하지 않는다면 기본적으로 staleTime이 0이므로, 쿼리를 fetch하자마자 해당 쿼리는 stale 상태가 된다.
위의 stale 데이터가 refetch 되는 조건들 중 첫번째 조건에 따라, getUserPortfolios 함수가 다시 호출되어 refetch가 이루어진다. (개발자 도구>네트워크 를 보면 쉽게 확인 가능하다.) 따라서 staleTime을 별도로 지정하지 않으면 react-query의 캐싱 기능을 제대로 활용하지 못하는 것이다. 캐싱만 될 뿐, 캐싱된 해당 쿼리를 전혀 활용하지 못하기 때문이다.
cacheTime은 말 그대로 쿼리가 캐시되어있는 시간을 말한다. react-query에서 설정한 디폴트 cacheTime은 300000(5분)이다. 따라서 캐시된 쿼리는 5분 동안 사용되지 않으면(inactive 상태) 저장되는 게 불필요하다고 판단되어 가비지 컬렉터가 수거해 가서 캐시에서 사라진다.
정적인 데이터 또는 변화가 적은 데이터는 자주 fetch할 필요 없으므로 staleTime을 길게 설정해도 좋다. staleTime을 Infinity로 설정해서 stale상태로 무한정 유지도 가능하다. 이 경우 강제로 refetch 하려면 invalidateQueries를 활용할 수 있다.
또한, staleTime을 설정할 때 cacheTime도 당연히 생각을 해야한다. 왜냐하면 staleTime이 아무리 길어도 cacheTime이 그에 비해 짧으면, 캐시가 사라져서 refetch가 불가피해지는 상황이 생길 수 있다.