나: tanstack query 에서
isError
로 에러 처리를 했음에도 처리가 안됩니다..
시니어:isLoading
,isError
는 어떤 순간에 변경 됩니까?
나: ...
그렇습니다. useQuery
, useMutation
등 tanstack query에서 사용하는 여러 가지 훅들은 자신의 진행도를 나타내는 상태를 반환하는데 그 상태가 어떤 단계에서 어떤 메세지를 가지고 있는지 명확하게 알고 있지 못했기 때문에 문제를 해결하기 위한 디버깅에 애를 먹었습니다.
해서 이번 기회에 tanstack query가 보여주는 진행 상태들이 어떤 형태로, 어떤 순간에 변화하는지 살펴보고자 합니다
공식 문서를 살펴보면 useQuery는 24개의 값을 반환하고 그 중 쿼링 과정에서 시간과 관련된 flag 역할을 하는 상태 8가지 상태를 알게 됐습니다.
isError
- fetch를 시도하는 과정에서 수신되 오류가 있음을 명시isFetched
- 쿼리를 가져온경우true
isFetching
- 쿼리를 가져오는 중임을 명시isPaused
- 쿼리를 가져오려고 했지만 중지된 상태isLoading
- 캐시된 데이터가 없고 쿼리 시도가 아직 완료되지 않은 경우isRefetching
- 초기 로딩이 아닌 백그라운드 리페칭이 진행중임을 명시isInitialLoading
- 초기 로딩임을 명시isSuccess
- 쿼리가 오류 없이 응답을 수신하고 데이터를 표시할 준비를 마친 상태(초기 패칭을 진행하지 않은 상태일때true
인 이유는initialData
를 표시하고 있어서)
공식 문서가 설명하는 8가지 상태 중, 알지 못했던 것은 아래 두가지였습니다.
isLoading
이 패치를 진행 중임을 명시할 뿐만 아니라 캐시 된 데이터가 없는 상황에서도 true
값을 가지고 있다는 것isLoading
& isFetching
의 구분이 모호해보인다는 점isLoading: true
??캐시 된 데이터가 없는 상황에서 isLoading
이 true
인 경우는 초기 fetch가 진행될 때가 유일하다고 생각했는데 이 부분은 반은 맞고 반은 틀렸습니다.
네트워크 모드 에서 Network Mode: online
상황에서 isLoading
은 fetch가 중단된(paused) 상황에서도 true
값을 가집니다. fetching은 네트워크 연결이 해제 됐을 때 pause 되는데 더 이상 진행되지 않는 상황에서도 isLoading
은 ture
값을 가지고 있습니다.
따라서 isLoading
을 활용해 로더를 사용한 경우 fetching이 paused된 경우를 처리하지 못합니다.
위와 같이 네트워크가 중단되는 상황에서 isLoading은 반응하지 못하고 이에 대응하기 위해 fetchStatus
를 제공합니다. 실제 queryFn이 실행되는 중임을 알려주는 상태가 isFetching
입니다.
useQuery에서 result를 만드는 메소드 소스코드를 살펴보면
fetchStatus = canFetch(query.options.networkMode)
? 'fetching'
: 'paused'
queryFn을 실행하기 전, 먼저 인터넷 상태를 확인합니다. 이때 isLoading
은 true
입니다.
fetchStatus
가 fetching 이든 paused 든 isLoading
에 대한 상태는 변하지 않습니다.
isLoading
이 true
인 상황에서 fetchStatus
는 fetching
값을 가지거나 paused
상태를 가질 수 있다는 것!
여기까지만 살펴본다면 'isLoading
을 굳이 사용할 필요가 있는가?' 라는 의문이 듭니다.
isFetching
이 언제나 isLoading
보다 옳은가?공식 문서에 따르면 isFetching
상태를 만들어주는 fetchState
를 사용하지 못하는 상황이 있는데 Network Mode: Always
상태에서 그렇습니다.
Network Mode: Always
상태에선 Tanstack Query는 온/오프라인 상관없이 queryFn
를 무조건 실행하기 때문에 인터넷 연결 상태를 확인하지 않습니다. 따라서 fetchStatus
값을 표시하지 않습니다. 다만 연결이 해제되어 queryFn
이 실행되지 못하면 error
상태가 되어 isError
가 true
로 표현됩니다.
Network Mode: Always
는 AsyncStorage
나 Promise
를 사용해 오프라인에서도 동작하는 작업을 useQuery
에서 사용해야할 때 설정합니다.
// query-core/src/queryObserver.ts
protected createResult(...
const isFetching = fetchStatus === 'fetching'
const isLoading = status === 'loading'
const isError = status === 'error',
...
isSuccess: status === 'success',
isInitialLoading: isLoading && isFetching,
isRefetching: isFetching && !isLoading,
isPaused: fetchStatus === 'paused',
...)
isLoading
, isError
, isFetching
등의 boolean
타입을 갖는 상태들은 status
, fetchStatus
의 상태를 단순 분기해서 만들었기 때문에 status
, fetchStatus
만을 사용해 진행 상태에 대한 분기 처리를 해도 무방합니다.isLoading
, isError
로 시도했던 예외 처리가 의도한 대로 작동을 하지 않았던 것은 isLoading
만으로 tanstack query 가 진행하는 모든 작업 상태를 판단할 수 없었기 때문입니다.useQuery
의 문제인지 비동기 통신 작업을 수행하는 라이브러리의 문제인지를 파악하는데 status
, fetchStatus
두 가지 모두 사용하는 것은 디버깅에 도움이 됩니다.