tanstack-query의 진행 상태

Peter·2023년 3월 27일
4

isError가 안먹어요

나: tanstack query 에서 isError로 에러 처리를 했음에도 처리가 안됩니다..
시니어: isLoading, isError는 어떤 순간에 변경 됩니까?
나: ...

그렇습니다. useQuery, useMutation 등 tanstack query에서 사용하는 여러 가지 훅들은 자신의 진행도를 나타내는 상태를 반환하는데 그 상태가 어떤 단계에서 어떤 메세지를 가지고 있는지 명확하게 알고 있지 못했기 때문에 문제를 해결하기 위한 디버깅에 애를 먹었습니다.

해서 이번 기회에 tanstack query가 보여주는 진행 상태들이 어떤 형태로, 어떤 순간에 변화하는지 살펴보고자 합니다

공식 문서(useQuery 설명 링크)

공식 문서를 살펴보면 useQuery는 24개의 값을 반환하고 그 중 쿼링 과정에서 시간과 관련된 flag 역할을 하는 상태 8가지 상태를 알게 됐습니다.

  • isError - fetch를 시도하는 과정에서 수신되 오류가 있음을 명시
  • isFetched - 쿼리를 가져온경우 true
  • isFetching - 쿼리를 가져오는 중임을 명시
  • isPaused - 쿼리를 가져오려고 했지만 중지된 상태
  • isLoading - 캐시된 데이터가 없고 쿼리 시도가 아직 완료되지 않은 경우
  • isRefetching - 초기 로딩이 아닌 백그라운드 리페칭이 진행중임을 명시
  • isInitialLoading - 초기 로딩임을 명시
  • isSuccess - 쿼리가 오류 없이 응답을 수신하고 데이터를 표시할 준비를 마친 상태(초기 패칭을 진행하지 않은 상태일때 true인 이유는 initialData를 표시하고 있어서)

공식 문서가 설명하는 8가지 상태 중, 알지 못했던 것은 아래 두가지였습니다.

  1. isLoading이 패치를 진행 중임을 명시할 뿐만 아니라 캐시 된 데이터가 없는 상황에서도 true 값을 가지고 있다는 것
  2. isLoading & isFetching 의 구분이 모호해보인다는 점

데이터가 없는 isLoading: true??

캐시 된 데이터가 없는 상황에서 isLoadingtrue인 경우는 초기 fetch가 진행될 때가 유일하다고 생각했는데 이 부분은 반은 맞고 반은 틀렸습니다.

네트워크 모드 에서 Network Mode: online 상황에서 isLoading은 fetch가 중단된(paused) 상황에서도 true 값을 가집니다. fetching은 네트워크 연결이 해제 됐을 때 pause 되는데 더 이상 진행되지 않는 상황에서도 isLoadingture 값을 가지고 있습니다.

따라서 isLoading 을 활용해 로더를 사용한 경우 fetching이 paused된 경우를 처리하지 못합니다.

isLoading & isFetching

위와 같이 네트워크가 중단되는 상황에서 isLoading은 반응하지 못하고 이에 대응하기 위해 fetchStatus 를 제공합니다. 실제 queryFn이 실행되는 중임을 알려주는 상태가 isFetching 입니다.

useQuery에서 result를 만드는 메소드 소스코드를 살펴보면

fetchStatus = canFetch(query.options.networkMode)
          ? 'fetching'
          : 'paused'

queryFn을 실행하기 전, 먼저 인터넷 상태를 확인합니다. 이때 isLoadingtrue입니다.
fetchStatus가 fetching 이든 paused 든 isLoading에 대한 상태는 변하지 않습니다.
isLoadingtrue인 상황에서 fetchStatusfetching 값을 가지거나 paused 상태를 가질 수 있다는 것!

여기까지만 살펴본다면 'isLoading을 굳이 사용할 필요가 있는가?' 라는 의문이 듭니다.

isFetching이 언제나 isLoading 보다 옳은가?

공식 문서에 따르면 isFetching 상태를 만들어주는 fetchState를 사용하지 못하는 상황이 있는데 Network Mode: Always 상태에서 그렇습니다.

Network Mode: Always 상태에선 Tanstack Query는 온/오프라인 상관없이 queryFn를 무조건 실행하기 때문에 인터넷 연결 상태를 확인하지 않습니다. 따라서 fetchStatus 값을 표시하지 않습니다. 다만 연결이 해제되어 queryFn이 실행되지 못하면 error 상태가 되어 isErrortrue로 표현됩니다.

Network Mode: AlwaysAsyncStoragePromise를 사용해 오프라인에서도 동작하는 작업을 useQuery에서 사용해야할 때 설정합니다.

소스코드에서 Flag

// 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 두 가지 모두 사용하는 것은 디버깅에 도움이 됩니다.
profile
컴퓨터가 좋아

0개의 댓글