본문 바로가기

FrontEnd

리액트 쿼리 : 네트워크 오프라인 시 동작

반응형

원문 : https://tkdodo.eu/blog/offline-react-query

오타가 너무 많았어서 수정하였습니다.

TL;DR : fetchStatus - 네트워크 연결 상태를 나타내는 횡단관심사

  • React Query는 비동기 상태 관리 도구 입니다.
  • queryFn의 리턴값이 프로미스인 이상, 라이브러리는 동작합니다.
    • 데이터가 어디에서 왔는지는 중요하지 않습니다.
  • fetchStatus는 loading, sucess,error와 직교하는 또 다른 상태입니다.
    • fetching: 쿼리가 실행중입니다 - 요청이 실행중입니다.
    • paused: 쿼리가 실행되고 있지 않습니다
      • 네트워크가 다시 연결될 때까지 쿼리가 일시 중지됩니다.
    • idle: 쿼리가 현재 실행중이지 않습니다.
  • v4의 기본 모드에서는 네트워크 연결이 없으면 쿼리하지 않습니다.
    • 상태는 paused 입니다.
  • v4에서 네트워크 연결 없을 시 중간 캐시 레이어를 따로 사용하려면(ex) pwa) offline first 모드를 사용합니다
  • 혹시 네트워크가 아니라 그냥 비동기 상태 관리자로 사용할 경우(ex 하이브리드 앱, asyncStorage) always를 사용합니다.

사용 방법과 관련 문서

  • 쿼리 / 뮤테이션 옵션에서 지정할 수 있음

https://tanstack.com/query/v4/docs/guides/network-mode#network-mode-online

 

Network Mode | TanStack Query Docs

React Query provides three different network modes to distinguish how Queries and Mutations should behave if you have no network connection. This mode can be set for each Query / Mutation individually, or globally via the query / mutation defaults. Since R

tanstack.com

https://tanstack.com/query/v4/docs/reference/useQuery

 

useQuery | TanStack Query Docs

const { data,

tanstack.com


Promise를 생성하는 방법에는 여러 가지가 있지만 가장 큰 사용 사례는 (서버에서) 데이터 가져오기입니다.
매우 자주 활성 네트워크 연결이 필요합니다.
러나 때때로, 특히 네트워크 연결이 불안정할 수 있는 모바일 장치에서는 앱이 네트워크 연결 없이도 작동해야 합니다.

V3 버전의 문제

네트워크 연결이 없어도, 쿼리를 중지하기 위해 쿼리를 재시도 해야 합니다.
 
React Query는 오프라인 시나리오를 처리하는 데 매우 적합합니다.
캐싱 레이어를 제공하기 때문에 캐시가 채워져 있는 한 네트워크 연결이 없어도 계속 작업할 수 있습니다.
v3 버전이 예상대로 작동하지 않는 몇 가지 극단적인 시나리오를 살펴보겠습니다.
설명을 위해 공식문서 예제를 사용하겠습니다. (example from the docs)

1) 데이터가 캐시에 없음

v3에서는 캐시가 채워지면 모든 것이 잘 작동합니다.
상황이 이상해지는 극단적인 시나리오는 다음과 같습니다.
  • 네트워크 연결이 양호할때 게시물 목록 보기로 이동합니다.
  • 연결이 끊어진 상태에서, 게시물을 클릭합니다.

다시 연결될 때까지 쿼리가 로딩 상태로 유지됩니다.

또한 브라우저 devtools에서 실패한 네트워크 요청을 볼 수 있습니다.
React Query는 항상 첫 번째 요청을 시작하고 실패할 경우 네트워크 연결이 끊어지면 재시도를 일시 중지하기 때문입니다.

React Query Devtools는 쿼리가 가져오는 중(fetching)임을 표시하지만 이는 사실이 아닙니다.

쿼리는 실제로 (재시도)일시 중지되었지만, 해당 상태를 나타내는 개념이 없습니다. 숨겨진 구현 세부 정보입니다.

 

2) 재시도가 불가능

마찬가지로 위의 시나리오에서 재시도를 모두 끈 경우 쿼리는 중지할 방법 없이 즉시 오류 상태가 됩니다.
네트워크 연결이 없는데도, 쿼리를 중지하기 위해 쿼리를 재시도 해야 하는 이유가 뭘까요 🤷‍♂️🤷‍♂️?

3) 네트워크 연결이 필요없는 쿼리

동작에 네트워크 연결이 필요하지 않은 쿼리
(예: web worker에서 값비싼 비동기 처리를 수행하기 때문에)는 다른 이유로 실패할 경우 네트워크 연결을 다시 얻을 때까지 일시 중지됩니다.
또한 네트워크에 연결되어 있지 않으면 해당 기능이 완전히 비활성화되기 때문에
이러한 쿼리는 창 포커스에서 실행되지 않습니다.

요약하면 두 가지 주요 문제가 있습니다.
  • React Query가 네트워크 연결이 필요하지 않은 경우에도 네트워크 연결이 필요하다고 가정하고(사례 3)
  • React Query가 쿼리를 실행하지 않아야 함에도 쿼리를 실행합니다. (사례 1 및 2)

The new NetworkMode

v4에서는 새로운 networkMode 설정으로 이 문제를 전체적으로 해결하려고 했습니다.
이를 통해 온라인 쿼리와 오프라인 쿼리를 명확하게 구분할 수 있습니다.
이는 useQuery와 useMutation에 대한 옵션입니다.
즉, 전역적으로 또는 쿼리별로 설정할 수 있습니다.
 
즉, 네트워크 연결이 필요한 쿼리와 그렇지 않은 쿼리가 있을 수 있습니다.
 

online

이것은 대부분의 사용자가 데이터 가져오기와 함께 React Query를 사용할 것으로 예상하기 때문에
v4의 새로운 기본 모드(default)입니다.
이 설정을 사용하면 활성 네트워크 연결이 있는 경우에만 쿼리를 실행할 수 있다고 가정합니다.
 
네트워크 연결이 필요하지 않은 쿼리를 실행하려는 경우 어떻게 될까요?
쿼리가 새로운 일시 중지(paused) 상태로 전환됩니다.
 
paused 상태는 쿼리의 idle,loading,success,error 기본 상태에 부차적인 것입니다. (직교)
언제든지 네트워크 연결이 끊어질 수 있기 때문입니다.
 
예를 들어 데이터를 한 번 성공적으로 가져왔지만 백그라운드 다시 가져오기가 일시 중지된 경우
success and paused 상태임을 의미합니다.
 
쿼리가 처음 탑재되는 경우 loading and paused일 수 있습니다.
 

fetchStatus

과거에 쿼리가 실행 중임을 나타내는 isFetching 플래그가 있었습니다.
새로운 paused 상태와 유사하게 쿼리는 success 및 fetching 또는 error 및 fetching 상태가 될 수 있습니다.
백그라운드 다시 가져오기는 가능한 많은 상태(👋 상태 머신)를 제공합니다.
 
fetching와 paused는 상호 배타적이므로 이제 useQuery에서 반환되는 새 fetchStatus로 결합했습니다.
 
  • fetching: 쿼리가 실행중입니다 - 요청이 실행중입니다.
  • paused: 쿼리가 실행되고 있지 않습니다 - 네트워크가 다시 연결될 때까지 쿼리가 일시 중지됩니다.
  • idle: 쿼리가 현재 실행중이지 않습니다.
일반적으로 쿼리 상태는 데이터에 대한 정보를 제공합니다.
success은 항상 데이터가 있음을 의미하고
loading는 아직 데이터가 없음을 의미합니다.
 
반면에 fetchStatus는 queryFn에 대한 정보를 제공합니다.
즉, isFetching 및 isPaused는 queryFn이 실행 중인지 아닌지에 대한 정보를 제공합니다.

위의 사례 1)이 v4에서 어떻게 보이는지 살펴보겠습니다.
  • paused: 쿼리가 실행되고 있지 않습니다 - 네트워크가 다시 연결될 때까지 쿼리가 일시 중지됩니다.
 
새로운 보라색 상태 배지로 인해 쿼리의 상태(paused)를 명확하게 볼 수 있습니다.
또한 네트워크를 다시 켜면 첫 번째 네트워크 요청이 이루어집니다.

always

이 모드에서 React Query는 네트워크 연결에 대해 전혀 신경 쓰지 않습니다.
쿼리는 항상 실행되며 paused되지 않습니다.
서버에서 데이터 가져오기가 아닌 다른 용도로 React Query를 사용할 때 가장 유용합니다.

offlineFirst 

이 모드는 v3에서 React Query가 작동하는 방식과 매우 유사합니다.
첫 번째 요청은 항상 이루어지며 실패하면 재시도가 paused 됩니다.
 
이 모드는 React Query 위에 브라우저 캐시와 같은 추가 캐싱 레이어를 사용하는 경우에 유용합니다.
GitHub repo API를 예로 들어 보겠습니다. 다음 응답 헤더를 보냅니다.
cache-control: public, max-age=60, s-maxage=60​

 

즉, 다음 60초 동안 해당 리소스를 다시 요청하면 브라우저 캐시에서 응답이 옵니다.
이것에 대한 멋진 점은 오프라인 상태에서도 작동한다는 것입니다!
service workers( 예: offline first PWAs)의 경우 네트워크 요청을 가로채고,
가능한 경우 캐시된 응답을 전달하여 유사한 방식으로 작동합니다.
디폴트 온라인 모드와 같이 네트워크 연결이 없기 때문에,
React Query가 요청을 실행하지 않기로 결정하면
해당 동작은 불가능합니다.
따라서 이 추가 캐시 계층이 있는 경우 offlineFirst networkMode를 사용해야 합니다.
 
첫 번째 요청이 나가서 캐시에 도달하면 쿼리가 성공 상태가 되고 해당 데이터를 얻게 됩니다.
그리고 캐시 누락이 있는 경우 네트워크 오류가 발생할 가능성이 높습니다.
그 후 React Query는 재시도를 일시 중지하여 쿼리를 일시 중지 상태로 만듭니다.
위의 사례1, 사례 2. 네트워크가 없을 때도 재시도에 적절합니다.

저에게 이것들이 무슨 의미가 있나요?

전혀 신경쓰지 않아도 됩니다.

여전히 새로운 fetchStatus를 무시하고 isLoading만 확인할 수 있습니다. - React Query는 이전과 같이 작동합니다.

(위의 예시 2)는 네트워크 오류를 표시하지 않을 수 있기 때문에 더 잘 작동합니다).

 

그러나 네트워크 연결이 없는 상황에서 앱을 강력하게 만드는 것이 우선순위라면

이제 fetchStatus에 따라 행동할 수 있는 옵션이 있습니다.

 

그 새로운 상태로 무엇을 하느냐는 당신에게 달려 있습니다.

사람들이 이를 이용해 어떤 ux를 구축할지 기대됩니다. 🚀
 

 

반응형