react-query의 Stale vs Cache 상태
둘의 차이점이 무엇일까
2024-03-09
react-query를 쓰면서 stale와 cache가 뭐지?하는 순간이 많았다. 둘의 차이를 명확히 알아보려고 한다.
먼저 react-query장점은 서버로부터 불러온 데이터를 적절한 캐싱 전략을 통해 불필요한 네트워크 호출을 줄여줄 수 있다는 점이다. react-query는 설정한 cacheTime(기본값 5분)만큼 데이터를 메모리에 저장해 놓는다.
그럼 이 메모리는 어떤 것일까? QueryCache를 쓴다고 한다. (보통 이 QueryCache를 직접 접근하지 않고 QueryClient를 사용한다.)
그럼 이 QueryCache는 실제 무엇이 저장되는 걸까? 코드를 살펴보면 다음과 같이 구성되어 있고, Query를 관리하는 역할을 하는 것이 QueryCache같이 보인다.
QueryCache의 객체를 살펴보면 아래와 같다.
- 쿼리들은 해시키를 바탕으로 Map형태로 관리한다.
- 이미 쿼리가 있는 경우 해당 쿼리를 queries에서 찾아서 가져온다.
- 쿼리가 없는 경우 새로운 쿼리를 만든다.
그럼 쿼리의 캐시가 존재하면 데이터를 다시 가져오지 않는걸까? 근본적으로 그럼 react-query를 쓸 때 어느 시점에 데이터를 가져오는걸까?
비동기 상태
리액트 쿼리가 다루는 상태는 일반적으로 쓰는 useState와 같은 상태와는 결이 다르다고 할 수 있다. 리액트 쿼리는 주로 비동기 데이터, 서버나 API로 받아온 데이터를 캐싱, 동기화 하는데 초점을 둔다. (당장 useQuery의 반환 값도 Promise이다.)
리액트 쿼리는 비동기 업데이트 작업을 다음의 특정 시점에서 수행한다.
- QueryKey가 수정되었을 경우
- 네트워크 연결이 다시 이뤄진 경우
- 컴포넌트의 마운트
- window의 포커스가 간 경우
다만 이 모든 작업은 오로지 stale한 Query에 대해서만 이루어진다. 다시 데이터를 패치할지 말지는 오로지 이 stale에 대해서만 의존적이다.
결국 캐싱이 있더라도, stale에 따라서, 다시 데이터 패칭을 할지 말지가 결정된다.
그럼 이 stale한 Query가 대체 무엇일까 ?
Stale
Stale의 뜻을 찾아보면 말라비틀어진, 탁한 이라는 뜻이 나온다.
staleTime으로 설정한 시간만큼(기본값인 0초이다) 데이터가 fresh상태로 있다가 이후 stale의 상태로 바뀌게 된다. 예를 들어 다음과 같이 staleTime을 설정한다면 600,000밀리초 (10분)동안 fresh 상태이고 그 이후 stale 상태로 바뀐다.
그리고 이 stale 상태이고 위에서 언급한 경우(컴포넌트가 마운트 된 경우)에 한해서 다시 데이터 패칭이 일어난다.
결국 staleTime을 어떻게 사용하는지가 제일 중요한 부분인 것 같다.
만약 staleTime이 0이라면, 항상 최신의 데이터나 빠르게 변하는 데이터에서 유용할 것이고, Infinity라면 서버가 재시작할때만 변화하는 것이 필요할 때 적절할 것이다.
Cache
이번에는 그럼 Cache에 대해 알아보자. 앞서 QueryCache가 Query라는 객체를 사용하는 것을 볼 수 있다. 그럼 이 Query라는 객체에 대해 더 살펴보자. 그리고 이 Query에 Cache가 어떻게 들어가 있는지도 알아보자!
그리고 이 GCTime을 갱신하고 수정하는 클래스는 removable에 정의되어 있다.
cache를 종합해보면 다음과 같다. 먼저 queryClient에서 QueryCache를 관리한다. QueryCache는 Query객체를 관리하는데, 이 Query객체의 옵션으로서 캐시를 설정할 수 있고, 이 캐시를 실제 가비지 컬렉션에서 제거, 업데이트, 예약하는 모든 과정은 Removable이라는 추상클래스에서 담당하는 구조로 이루어져 있다.
보통 cacheTime을 옵션으로서 정해주는데, 이것은 비활성화된 쿼리가 캐시에서 제거될떄까지의 시간을 의미한다.
즉, 특정 쿼리를 사용하는 모든 컴포넌트의 언마운트 시점에서 이 쿼리는 비활성화된 쿼리가 된다. 결국 cacheTime은 쿼리가 활성화 되어 있으면 아무역할을 하지 않는다.