[WizSched] QueryErrorResetBoundary 적용, 에러 처리
🍀 목차
설계
QueryErrorResetBoundary?
구현
설계
개발하며 마주친 401, 403 등의 에러들을 어떻게 처리할지 고민했다. 사용자 입장에서 어떤 에러가 발생했는지 알 수 있게 최대한 상수화해 보자는 생각이 들었다.
작성은 Google Calendar 가이드 API 오류 처리 항목을 참고했다. 401, 403 에러인 경우 재로그인을 해야 하므로 redirect
변수를 true로 주었다.
const ERRORS: ErrorMap = {
400: {
message: '잘못된 요청입니다.💦',
redirectState: {
redirect: false,
},
},
401: {
message: '잘못된 인증 정보입니다. 재로그인 해주세요.💦',
redirectState: {
redirect: true,
path: RoutePath.LOGIN,
},
},
// ...
0: {
message:
'예상치 못한 오류가 발생했습니다. 계속해서 같은 문제 발생 시, 개발자에게 문의해주세요.🐛',
redirectState: {
redirect: false,
},
},
} as const;
그 외 예상치 못한 오류는 key값 0으로 매치시켰다.
QueryErrorResetBoundary?
TanStack Query의 QueryErrorResetBoundary
는 쿼리에 suspense를 사용하는 경우 오류 발생 후 렌더링 시 쿼리를 다시 시도할 수 있다. 사용법은 아래와 같다.
import { QueryErrorResetBoundary } from '@tanstack/react-query'
import { ErrorBoundary } from 'react-error-boundary'
const App: React.FC = () => (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ resetErrorBoundary }) => (
<div>
There was an error!
<Button onClick={() => resetErrorBoundary()}>Try again</Button>
</div>
)}
>
<Page />
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
)
ErrorFallback
컴포넌트가 있기 때문에 위 예시코드의 fallbackRender
프로퍼티를 FallbackComponent
로 바꿔주었다.
구현
기존 CalendarSelector
에 QueryErrorResetBoundary를 적용시킨다.
import { QueryErrorResetBoundary } from '@tanstack/react-query';
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import ErrorFallback from '@/components/fallback/ErrorFallback';
import LoadingFallback from '@/components/fallback/LoadingFallback';
// ...
const CalendarSelector = () => {
return (
<div className="py-4">
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary onReset={reset} FallbackComponent={ErrorFallback}>
<Suspense fallback={<LoadingFallback />}>
<CalendarDropDown />
</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
</div>
);
};
export default CalendarSelector;
에러 텍스트만 띄우던 ErrorFallback도 개선한다.
props로 전달받은 error
를 만들어둔 에러 상수 객체와 연결, resetErrorBoundary
를 재시도 버튼 클릭 시 onClick 이벤트로 연결해 준다.
import { FallbackProps } from 'react-error-boundary';
import { useNavigate } from 'react-router-dom';
import Button from '@/components/button/Button';
import ERRORS from '@/constants/errors';
import useSupabaseAuth from '@/hooks/useSupabaseAuth';
const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => {
const navigate = useNavigate();
const { logOutWithGoogle } = useSupabaseAuth();
const statusCode = error.response.status || 0;
const errorMessage = ERRORS[statusCode].message;
const redirectState = ERRORS[statusCode].redirectState;
const handleLogoutAndRedirect = (path: string) => {
logOutWithGoogle();
navigate(`/${path}`);
};
return (
<>
<p>{errorMessage}</p>
{redirectState.redirect ? (
<Button
variant="contained"
color="secondary"
onClick={() => handleLogoutAndRedirect(redirectState.path)}
>
페이지 이동
</Button>
) : (
<Button variant="contained" color="error" onClick={resetErrorBoundary}>
재시도
</Button>
)}
</>
);
};
export default ErrorFallback;
const handleLogoutAndRedirect = (path: string) => {
logOutWithGoogle();
navigate(`/${path}`);
};
재로그인이 필요한 경우는 버튼 클릭 시에 로그아웃 후 로그인 페이지로 이동시켰다.
문서에서는 데이터에 대한 응답일 경우 redirect
사용을 권장하지만, 해당되지 않는다고 생각하여 useNavigate
hook을 사용하였다. 함수 이름을 handleLogoutAndNavigate
로 해야 하나 했지만 상수에서 redirectState로 관리해서... Redirect를 붙이기로 결정했다.
참고자료
https://developers.google.com/calendar/api/guides/errors?hl=ko
https://reactrouter.com/en/main/hooks/use-navigate
https://tanstack.com/query/latest/docs/framework/react/reference/QueryErrorResetBoundary