🔥 React Query에서의 상태 확인
React Query의 큰 장점은 쿼리 상태 필드에 쉽게 접근할 수 있다는 점입니다. 쿼리가 로딩 중인지 오류가 발생했는지 즉시 알 수 있죠. 이를 위해 라이브러리는 내부 상태 기계에서 주로 도출된 여러 불리언 플래그를 제공합니다. 타입을 살펴보면, 쿼리는 다음 상태 중 하나를 가질 수 있습니다:
success
: 쿼리가 성공했고 데이터를 가지고 있습니다.error
: 쿼리가 실패했고 오류가 설정되었습니다.pending
: 쿼리에 데이터가 없습니다.
isFetching
플래그는 내부 상태 기계의 일부가 아닙니다. 이는 요청이 진행 중일 때마다 참이 되는 추가 플래그입니다. 요청 중이면서 성공 상태일 수 있고, 요청 중이면서 오류 상태일 수 있습니다. 하지만 로딩 중이면서 동시에 성공 상태일 수는 없습니다. 상태 기계가 이를 보장합니다.
업데이트 사항
v5 이전에는 pending
이 loading
이라는 이름을 사용했고, v4 이전에는 idle
이라는 네 번째 상태가 있었습니다.
또한, isFetching
플래그는 isPaused
플래그와 마찬가지로 보조 fetchStatus
에서 도출됩니다. 이에 대해 자세히 알고 싶다면 #13: 오프라인 React Query를 읽어보세요.
일반적인 예제
대부분의 예제는 다음과 같은 모습을 보입니다:
const todos = useTodos() if (todos.isPending) { return '로딩 중...' } if (todos.error) { return '오류가 발생했습니다: ' + todos.error.message } return <div>{todos.data.map(renderTodo)}</div>
javascript
여기서는 먼저 대기 중인지와 오류가 있는지 확인한 후 데이터를 표시합니다. 일부 상황에서는 괜찮을 수 있지만, 다른 경우에는 적합하지 않을 수 있습니다. 많은 데이터 가져오기 솔루션, 특히 직접 만든 것들은 다시 가져오기 메커니즘이 없거나 사용자의 명시적인 상호작용에 의해서만 다시 가져옵니다.
하지만 React Query는 다릅니다.
기본적으로 매우 적극적으로 다시 가져오며, 사용자가 직접 요청하지 않아도 이를 수행합니다. refetchOnMount
, refetchOnWindowFocus
, refetchOnReconnect
개념은 데이터를 최신 상태로 유지하는 데 좋지만, 이런 자동 백그라운드 다시 가져오기가 실패하면 사용자 경험에 혼란을 줄 수 있습니다.
백그라운드 오류
많은 상황에서 백그라운드 다시 가져오기가 실패하면 조용히 무시해도 됩니다. 하지만 위의 코드는 그렇게 하지 않습니다. 두 가지 예를 살펴보겠습니다:
- 사용자가 페이지를 열고 초기 쿼리가 성공적으로 로드됩니다. 한동안 페이지에서 작업하다가 이메일을 확인하기 위해 브라우저 탭을 전환합니다. 몇 분 후 돌아오면 React Query가 백그라운드에서 다시 가져오기를 수행합니다. 이때 이 가져오기가 실패합니다.
- 사용자가 목록 보기 페이지에 있다가 한 항목을 클릭해 상세 보기로 들어갑니다. 이는 잘 작동하므로 목록 보기로 돌아갑니다. 다시 상세 보기로 들어가면 캐시의 데이터를 볼 수 있습니다. 이는 좋습니다. 단, 백그라운드 다시 가져오기가 실패하는 경우는 예외입니다.
두 상황 모두 쿼리는 다음과 같은 상태가 됩니다:
{ "status": "error", "error": { "message": "문제가 발생했습니다" }, "data": [{ ... }] }
json
보시다시피 오류와 오래된 데이터가 모두 있습니다. 이것이 React Query의 장점입니다. 스테일-와일-리밸리데이트 캐싱 메커니즘을 채택해 오래된 데이터라도 있다면 항상 제공합니다.
이제 우리가 무엇을 표시할지 결정해야 합니다. 오류를 보여주는 게 중요할까요? 오래된 데이터만 보여주는 게 충분할까요? 아니면 둘 다 보여주되 작은 '백그라운드 오류' 표시를 추가해야 할까요?
이 질문에 명확한 답은 없습니다. 구체적인 사용 사례에 따라 다릅니다. 하지만 위의 두 예를 고려하면, 데이터가 오류 화면으로 대체되는 것은 사용자에게 다소 혼란스러운 경험일 수 있습니다.
React Query가 기본적으로 실패한 쿼리를 지수 백오프로 세 번 재시도한다는 점을 고려하면 이는 더욱 중요합니다. 오래된 데이터가 오류 화면으로 대체되기까지 몇 초가 걸릴 수 있습니다. 백그라운드 가져오기 표시기가 없다면 정말 당황스러울 수 있죠.
그래서 저는 보통 데이터 가용성을 먼저 확인합니다:
const todos = useTodos() if (todos.data) { return <div>{todos.data.map(renderTodo)}</div> } if (todos.error) { return '오류가 발생했습니다: ' + todos.error.message } return '로딩 중...'
javascript
다시 말하지만, 사용 사례에 따라 크게 달라지기 때문에 무엇이 옳다고 명확히 말할 수 있는 원칙은 없습니다. 적극적인 다시 가져오기가 초래하는 결과를 모두가 인식해야 하며, 단순한 할 일 예제를 엄격히 따르기보다는 그에 맞게 코드를 구성해야 합니다.
이 패턴의 상태 확인이 일부 상황에서 해로울 수 있다는 점을 처음 강조해 준 Niek Bosch에게 특별히 감사드립니다.