-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ Feat ] 에러 처리를 위한 Error-boundary 적용 #184
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정성스러운 pr 작성 감사합니다! 에러 바운더리의 정의 정도만 알고 있었는데, 적용 방법과 상세 설명덕분에 완벽하게는 아니지만 이해할 수 있었습니다. 또한, 라이프사이클에 대해서도 명확한 이해가 필요하겠다고 느꼈네요. 아래는 리액트 공식 페이지에서 Error-Boundary 관련한 문서인데 다른분들도 참고하면 좋을거 같아서 남겨봅니다. 고생하셨습니다.
https://ko.legacy.reactjs.org/docs/error-boundaries.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
에러 바운더리라는 개념에 대해 처음 알게 되었는데요! 덕분에 대략적으로나마 이해할 수 있었습니다 에러만 따로 처리하면 관심사가 분리되어 관리하기 더 편리하겠네용
저도 이참에 에러처리, 권한 분리, 생명주기 등등에 대해 더 공부해봐야 될 것 같네요…! 자세한 설명 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pr에서 자세히 설명해 주신 덕분에 각 코드가 어떤 역할을 하는지 더 잘 이해할 수 있었습니다! 이와 같이 에러 관련 관심사를 분리함으로써 앞으로 더 명료히 코드를 작성할 수 있을 것 같아 기대됩니다. 항상 대원님 코드를 보면서 항상 많이 배우는 것 같아요. 고생 많으셨습니다! 👍🏻
static getDerivedStateFromError(error: AxiosError | Error): ApiErrorBoundaryState { | ||
// 에러를 특정 API 에러로 가정하고 처리할 수 있는지 확인 | ||
if ( | ||
error instanceof AxiosError && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
비교연산자를 사용해 error가 AxiosError의 인스턴스인지 판단하셨군요! instanceof 연산자를 실제로 사용해 본 경험이 많지 않은데 이렇게 활용될 수 있음을 배우고 갑니다!
|
||
class GlobalErrorBoundary extends Component<GlobalErrorBoundaryProps, GlobalErrorBoundaryState> { | ||
constructor(props: GlobalErrorBoundaryProps) { | ||
super(props); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super()이 아닌 super(props)를 사용하는 이유, super()이 반드시 사용되어야 하는가라는 의문점이 있었는데 이번 기회에 왜 그렇게 사용되는지 아티클을 찾아 보았습니다. 저와 같은 궁금증을 가진 분들이 읽어 보시면 좋을 것 같아요!
https://min9nim.github.io/2018/12/super-props/
- 쿼리 클라이언트 ThrowOnError 속성을 true로 변경하여 에러를 throw 할수 있게 끔하였습니다. - router 폴더를 생성해 관련 파일들 한곳에서 정리하였습니다. - UI가 없어서 임시 fallback을 문구가 있는 버튼으로 대체하였습니다.
7d74bfc
to
6917ec6
Compare
🔥 Related Issues
✅ 작업 리스트
🔧 작업 내용
(현재 UI가 나오지 않아, UI는 모두 임시로 작업하였습니다.)
시작
에러 처리에 대한 고민을 많이 했고, 그 과정에서 선언적으로 에러 처리를 할 수 있는
ErrorBoundary
를 사용하게 되었는데요.페이지에서는 데이터가 제대로 받아올 수 있는 경우만을 처리하고, 에러 관련사항은 에러바운더리에서 처리하는게
관심사
를 더 분리할 수 있는 방법이라고 생각하여 적용하게되었습니다.에러 구분
이 때 에러를
예측 가능한 에러
와,예측할 수 없는 에러
로 구분하여 처리하고 싶었습니다. 그래서 카카오테크 블로그를 참고해 두가지 에러 바운더리를 구현하였습니다.GlobalErrorboundary
: 클라이언트 입장에서 예측하기 힘든 에러 처리 ( 알수없는 에러, 네트워크 에러, 서버 점검 중 등등)ApiErrorBoundary
: 클라이언트 입장에서 어느정도 예측가능한 api 에러 ( 401,403,404,413 ... )그래서 Global에러는 큰 화면에서 retry 버튼이 있는 구조로 UI를 적용하고, Api에러는 부분적인 error fallback UI를 적용하고자 했습니다.
(디자인팀에게 문의 완료)
다른 방법
react-query
의QueryErrorResetBoundary
리액트쿼리 공식문서를 보면
QueryErrorResetBoundary
를 통해서 API에러를 처리할 수 있지만query
에러만 처리 가능하고,mutation
에러까지 처리할 수 있는 에러 바운더리는 제공하지 않더라구요. 그래서 직접 만들어서 사용하게 되었습니다.https://tanstack.com/query/latest/docs/framework/react/reference/QueryErrorResetBoundary#queryerrorresetboundary
GlobalErrorboundary
/ApiErrorBoundary
구현의도한 동작
에러가 throw되게 되면 가장 가까운 부모 로 전달이 되게 됩니다. 두 에러바운더리에서 의도한 플로우는 다음과 같습니다.
ApiErrorBoundary
로 해당 에러를 전달 받아서 처리ApiErrorBounday
에서 예측 가능한 경우가 아니라면 다시 error throwGlobalErrorBounday
에서 해당 에러를 전달 받아서 처리코드 설명
에러 바운더리 코드는 클래스로 작성되어 있어 클래스가 익숙하지 않다면 이해가 어려울 수 있습니다. 공식문서를 참고하는것을 추천드릴게요.
두 에러바운더리 모두 구조가 비슷하므로
ApiErrorBoundary
를 코드를 설명드리겠습니다. 주석 설명 읽어주시면 됩니다.사용 방법
ApiErrorBoundary
는 필요한 컴포넌트(api 통신을 하는 컴포넌트)에 적용Api에러는 모두 에러바운더리에서 처리하므로
react-query
의error
객체는 사용할 필요가 없겠죠?router 폴더 생성하여 관련 파일 정리 및 라우트 구조 변경
router
폴더 생성라우트를 보려고 왔다갔다하는것 같아서 비슷한 코드들을 가까운곳에 배치했어유
routesConfig에 url 명과 url이 담긴 상수 객체를 정의해놨습니다.
router 구조 변경
라우터는 로그인이 필요한 부분과 필요하지 않은 부분, 그리고 404페이지로 분리하였습니다.
ProtectedRoute는 로그인 기능이 제대로 구현되면 로그인을 하지 않은 사용자를 다시
login
페이지로 리다이렉션 해야되기 때문에 생성했습니다.(권한관련 로직) - 기존의권한 로직
은hoc
로페이지
를 일일이 감싸서권한 로직
을 부여 했지만,라우터 방식
으로 권한로직을 적용하면상위 라우터의의 로직
으로하위 라우터
에 동일한 로직을 적용할 수 있기 때문에 방식을 변경하였습니다.이와 관련해서 궁금하신 분들은 react의 권한 분리에 대해서 공부해보시면 좋을것 같습니다.
대표적으로
라우트 기반 권한 분리
와컴포넌트 기반 권한 분리
가 있습니다.🧐 새로 알게된 점
react-query
에서error-boundary
를 적용하기 위해서는queryClient
에서throwOnError
(과거useErrorBoundary
)를true
로 설정하여 에러를 throw할수 있게 해야합니다.🤔 궁금한 점
prettier 설정 변경하여 빨간줄 뜨면 vscode 한번 껐다가 키시면 됩니다!!
📸 스크린샷 / GIF / Link
에러바운더리 정상 작동!
20240917 이후 UI 적용 된 내용
ApiErrorBoundary
,GlobalErrorBoundary
UI 적용 - (단순 UI 구성입니다.)GlobalErrorBoundary
는 적용되어있는 상태이고ApiErrorBoundary
는 API 함수가 동작하는 하위 컴포넌트 아래 감싸서 사용해야합니다.ApiErrorBoundary
,GlobalErrorBoundary
UI 구현ApiErrorBoundary 사용법
다음과 같이 사용