react-query 문서에서는 자신들의 핵심적인 기능으로 queryClient, useQuery, useMutation을 소개하고 있다. (https://react-query.tanstack.com/quick-start)
일반적인 프로젝트에서는 이 세 기능을 주로 사용한다고하니 우선 이 세 기능을 익히고서 이후에 필요할 때 심화적인 학습을 하는 방식으로 진행해보자.
Important Defaults (중요한 기본값들)
Doc : https://react-query.tanstack.com/guides/important-defaults
기본적인 세 기능(queryClient, useQuery, useMutation)을 사용하기 위해서 알고 있어야 하는 기본적인 설정들이다. 문서에 따르면 합당한 수준에서의 aggressive한 기본값들을 가지고 있는데 내가 읽어보고 나름대로 정리해보자면 다음과 같다.
staleTime과 stale 상태에 대해서
react-query에서는 데이터가 한 번 fetch된 후 staleTime이 지나면 해당 데이터를 'stale'한 상태라고 지정함.
예를 들어 staleTime 이 5초다 ⇒ 데이터를 페칭해왔다 (fresh 상태) ⇒ 5초가 지났다 ⇒ stale 상태가 된다.
stale 상태가 되지 않게 만들려면 단순히 staleTime을 Infinity로 주면 된다.
stale한 상태가 되면 다음과 같은 경우에 다시 fetch한다.
- New instances of the query mount
- The window is refocused (유저가 다른 작업하다가 다시 typed에 돌아오면 다시 fetch)
- The network is reconnected.
- The query is optionally configured with a refetch interval. (refetch 설정을 명시적으로 준 경우)
특히 개발 단계에서는 필연적으로 react-query dev tools랑 window랑 코더가 마우스를 왔다갔다 하게 되므로 다시 브라우저 윈도우가 refocused되니까 refetch가 많이 일어나는 현상을 자연스러운 것이니 놀라지 말라고...
cacheTime에 대해서
기본값은 1000 * 60 * 5 ms. 즉, 5분임. 어디에 캐싱되는가? memory에 캐싱됨.
cacheTime 지나면 GC에 의해 수집됨. GC에 의해 수집되지 않게 하고 싶다면 If set to Infinity, will disable garbage collection.
staleTime과 cacheTime이 비슷해보이는데, 둘의 차이에 대해서는 후술할 것이다.
retry, retryDelay 옵션
기본값이 3임. query가 실패하면 자동으로 retryDelay 시간이 지난 후 다시 fetch하고, 다 실패하면 그제서야 error 반환함.
query 결과값에 대한 레퍼런스 유지
쿼리 결과는 기본적으로 공유되어 데이터가 실제로 변경되었는지 감지하고, 변경되지 않은 경우 데이터 참조가 변경되지 않는다고 함.
쉽게 말해서 {name: ‘darren’} 이란 json을 받은 후, 다시 refetching 되었는데 결과값이 같은 {name: ‘darren’}을 반환하였다면, reference type임에도 불구하고 같은 참조값을 가진 결과물을 반환한다는 것임. 같은 값을 가진 객체를 메모리에 다시 할당하지 않으므로 메모리상 이점이 있을 것으로 판단됨.
그 밖에 개인적으로 알게 된 것
- useQuery와 useMutation은 각각 언제 써야 하는가?
문서에 따르면 server에 있는 데이터를 변경하는 요청일 경우에는 useMutation을 쓰라고 함.
mutations are typically used to create/update/delete data or perform server side-effects.
우리 서비스가 query/service 로 분할되어 있으니 query에서는 useQuery, service에서는 useMutation을 사용하면 되지 않을까하는 막연한 생각이 듦.
단순히 생각하면 GET에는 useQuery, 그 외 POST/PATCH/DELETE 등에선 useMutation 사용하면 될 듯.
2. staleTime과 cacheTime은 도대체 뭐가 다른 건가?
react-query에서 작동하는 staleTime과 cacheTime이 동작하는 방식은 다음과 같다.
- query 인스턴스가 mount된다. (useQuery, useMutation을 사용한 컴포넌트가 마운트 → 마운트)
- 데이터를 fetching하고, 반환 값을 캐싱함
- 반환된 데이터는 staleTime 시간 만큼 지난 후 fresh 에서 stale 상태로 변경됨
- query 인스턴스가 unmount 됨 (useQuery, useMutation을 사용한 컴포넌트가 언마운트 → 언마운트)
- query instance가 unmount된 후에는 주어진 cacheTime 만큼 캐싱됨.
- cacheTime이 지나기 전에 쿼리 인스턴스가 새롭게 mount되면, 다시 데이터가 fetching되기 전까지는 캐싱된 내용을 보여주는 한편 뒤에서는 다시 fetching을 한다. 이를 백그라운드에서 fetching 된다라고 표현함
(실험해 볼 것)
- 데이터가 fetch 되었다. 이 때 query의 staleTime은 100초로 주었다.
- 다른 경로로 이동하여 컴포넌트가 언마운트 되었다.
- 곧바로 뒤로 가기를 눌러 다시 돌아왔을 때 쿼리 인스턴스가 마운트되어도 staleTime이 지나지 않았음로 다시 fetch가 되지 않을 것이다. (예상)
3. loader 조건에 대해서
https://react-query.tanstack.com/guides/background-fetching-indicators
status == 'loading'(isLoading) 을 기준으로 로더를 돌리는 것은, 첫번째 fetch일 때는 정상적인 것처럼 보인다. 그런데 react-query의 특성상 cache되어 있는 값을 보여주다가 백그라운드에서 refetch된 후 값이 바뀐다면, 유저들은 "왜 갑자기 화면이 바뀌었지" 라는 생각을 하게 될 것이다.
이럴 경우에는 백그라운드에서 fetch되는 것을 감지할 필요가 있고, 이럴 때 isFetching을 사용하면 된다고 한다. 결론적으로는, isLoading보다 isFetching을 로더의 기준으로 삼는 것이 좋아보인다.
QueryClient, QueryClientProvider
Doc
https://react-query.tanstack.com/reference/QueryClient
https://react-query.tanstack.com/reference/QueryClientProvider
queryClient는 글로벌한 레벨에서 동작한다.
프로젝트에 글로벌한 기본값 설정(ex - cacheTime), query 전 prefetchQuery 등 추가적 기능 포함.
// Create a client
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: Infinity, // 한 번 fetch 되면 영원히 fresh 상태가 됨. stale 그런거 없음.
},
},
});
function App() {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
);
}
컴포넌트 단에서 QueryClient가 직접 필요한 경우에는 useQueryClient 훅을 사용하면 됨.
import { useQueryClient } from 'react-query'
const queryClient = useQueryClient()
React Query Dev Tools
https://react-query.tanstack.com/devtools
react-query 3버전 이전에는 별도 설치 필요하였음. 그러나 최신 버전인 3버전 부터 devtools가 내장되기 시작함.
단, react-native 환경에서는 react-query-native-devtools라는 별도의 툴을 설치해야 함.
import { ReactQueryDevtools } from 'react-query-devtools'
function App() {
return (
<>
{/* The rest of your application */}
<ReactQueryDevtools initialIsOpen={false} />
</>
)
}
'State Management > react-query' 카테고리의 다른 글
react-query를 이해하는 몇가지 지식과 질문들 (2) | 2021.10.28 |
---|