jineecode
React-query의 에러 핸들링 본문
네트워크 요청이 실패하면 이상적으로는 쿼리가 오류 상태가 되기를 원할 것입니다. 그렇게 하지 않고 대신 성공한 쿼리가 표시 된다면 이는 queryFn 이 실패한 Promise를 반환하지 않았음을 의미합니다.
React Query는 상태 코드나 네트워크 요청에 대해 전혀 알지 못합니다(또는 신경 쓰지 않습니다). queryFn 이 제공 해야 하는 해결되거나 거부된 Promise가 필요합니다.
React Query가 거부된 Promise를 발견하면 잠재적으로 재시도를 시작하고 오프라인인 경우 쿼리를 일시 중지하고 결국 쿼리를 오류 상태로 만들 수 있으므로 올바르게 수행하는 것이 매우 중요합니다.
오류를 올바르게 처리하려면 React Query에서 거부(rejected)된 Promise가 필요합니다. 운 좋게도, 이것은 여러분이 axios와 같은 라이브러리를 다룰 때 얻을 수 있죠.
만약 당신이 fetch API 또는 4xx나 5xx와 같은 잘못된 상태 코드에 대해 거부된 Promise를 제공하지 않는 다른 라이브러리를 사용하고 있다면, 당신은 직접 queryFn을 통해 변환해야 합니다.
1. fetch API 를 쓸 경우
- 잘못된 코드
useQuery(['todos', todoId], async () => {
const response = await fetch('/todos/' + todoId)
// 🚨 4xx or 5xx are not treated as errors
return response.json()
})
- 아래처럼 예외처리를 반드시 해주세요!!!
useQuery(['todos', todoId], async () => {
const response = await fetch('/todos/' + todoId)
if (!response.ok) {
throw new Error('Network response was not ok')
}
return response.json()
})
2. 로깅
두 번째로, 로깅 목적으로 queryFn 내부에서 오류가 포착된다는 것입니다.
catch에서 오류를 다시 발생시키지 않으면 암시적으로 성공한 Promise를 다시 반환합니다.
- 잘못된 코드
useQuery(['todos', todoId], async () => {
try {
const { data } = await axios.get('/todos/' + todoId)
return data
} catch (error) {
console.error(error)
// 🚨 here, an "empty" Promise<void> is returned
}
})
- 아래처럼 failed Promise를 반환해주세요!
useQuery(['todos', todoId], async () => {
try {
const { data } = await axios.get('/todos/' + todoId)
return data
} catch (error) {
console.error(error)
// ✅ here, a failed Promise is returned
throw error
}
})
- 물론 useQuery의 onError 콜백을 사용해도 됩니다.
useQuery(
['todos', todoId],
async () => {
const { data } = await axios.get('/todos/' + todoId)
return data
},
{ onError: (error) => console.error(error) }
)
3. ErrorBoundary
오류 경계(Error Boundaries)는 렌더링 중에 발생하는 런타임 오류를 포착하기 위한 리액트의 개념으로, 이를 통해 적절하게 반응하여 폴백 UI로 표시할 수 있습니다.
컴포넌트를 원하는 세분화로 ErrorBoundary를 래핑할 수 있으므로 나머지 UI는 해당 오류의 영향을 받지 않습니다.
ErrorBoundary는 렌더링 중에 발생하지 않기 때문에 비동기 오류를 포착할 수 없습니다.
ErrorBoundary가 React Query에서 동작하기 위해
1. 내부적으로 오류를 잡아
2. 다음 렌더링 주기에 다시 던져(throw)
3. 오류 경계가 오류를 선택할 수 있도록 합니다.
이것은 매우 천재적이면서도 간단한 오류 처리 방식이며, 이 작업을 수행하기 위해 필요한 것은 useErrorBoundary 플래그를 쿼리에 전달(또는 기본 구성을 통해 제공)하는 것입니다.
useErrorBoundary라는 함수는 오류 경계로 이동할 오류와 지역적으로 처리할 오류를 지정할 수도 있습니다.
useQuery(['todos'], fetchTodos, {
// 🚀 only server errors will go to the Error Boundary
useErrorBoundary: (error) => error.response?.status >= 500,
})
이것은 mutations에도 효과가 있으며, form을 제출 할 때 매우 유용합니다. 4xx 범위의 오류는 지역적으로 처리할 수 있는 반면(예: 백엔드 유효성 검사에 실패한 경우), 모든 5xx 서버 오류는 오류 경계로 전파될 수 있습니다.
4. 토스트 에러
전역에 등록하면, 각 쿼리에 대해 한 번만 오류 토스트가 표시됩니다.
import toast from 'react-hot-toast'
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
toast.error(`Something went wrong: ${error.message}`),
}),
})
5. 적절하게 섞어 쓰기
React Query에서 오류를 처리하는 세 가지 주요 방법은 다음과 같습니다.
- useQuery에서 반환된 오류 속성
- onError 콜백(쿼리 자체 또는 글로벌 QueryCache/MutionCache)
- ErrorBoundary 사용
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
// 🎉 only show error toasts if we already have data in the cache
// which indicates a failed background update
if (query.state.data !== undefined) {
toast.error(`Something went wrong: ${error.message}`)
}
},
}),
})
'React-Query' 카테고리의 다른 글
Error: Missing queryFn (0) | 2022.08.02 |
---|