-
[WizSched] QueryErrorResetBoundary 적용, 에러 처리Front-End/Project 2024. 4. 2. 22:46
🍀 목차
설계
QueryErrorResetBoundary?
구현설계
개발하며 마주친 401, 403 등의 에러들을 어떻게 처리할지 고민했다. 사용자 입장에서 어떤 에러가 발생했는지 알 수 있게 최대한 상수화해 보자는 생각이 들었다.
정확히 어떤 에러가 발생했는지 보여주고 싶었다. 작성은 Google Calendar 가이드 API 오류 처리 항목을 참고했다. 401, 403 에러인 경우 재로그인을 해야 하므로
redirect
변수를 true로 주었다.API 오류 처리 가이드 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;
404 에러의 경우 401 or 403 에러의 경우 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