static getDerivedStateFromError()
와 componentDidCatch()
중 하나(혹은 둘 다)를 정의하면 클래스 컴포넌트 자체가 error boundary가 된다.static getDerivedStateFromError()
를 사용componentDidCatch()
를 사용error boundary는 다음과 같은 에러는 포착하지 않는다
- 이벤트 핸들러
- 비동기적 코드 ( 예:
setTimeout
혹은requestAnimationFrame
콜백 )- 서버 사이드 렌더링
- 자식에서가 아닌 error boundary 자체에서 발생하는 에러
자세한 내용은 참고한 링크에서 볼 수 있다.
알아본 결과 error boundary를 작성할 때 함수형으로 작성할 방법이 없다고 한다.
그래서 클래스 형태로 작성하게 되는데 error-boundary라이브러리를 사용하면 error boundary를 따로 구현하지 않고 사용할 수 있다.
npm install react-error-boundary
간단한 예제로 사용해봤다
// errorFallback.jsx
const ErrorFallBack = ({ error, resetErrorBoundary }) => {
let errorMsg = "예기치 못한 에러가 발생했습니다.";
switch (error.status) {
case 401:
errorMsg = "인증되지 않은 사용자입니다.";
case 404:
errorMsg = "요청한 페이지를 찾을 수 없습니다.";
case 500:
errorMsg = "서버에서 에러가 발생했습니다.";
}
return (
<div>
<p>{errorMsg}</p>
<p> 상세 : {error.message}</p>
<button onClick={() => resetErrorBoundary()}>재시도</button>
</div>
);
};
export default ErrorFallBack;
//errorComponent
// 에러가 발생한 컴포넌트
const ErrorComponent = ({ error }) => {
const err = new Error();
err.message = "에러 발생 컴포넌트";
err.status = error;
throw err;
};
export default ErrorComponent;
간단하게 3가지의 에러사항만 설정해주었다.
테스트해보기 위해 전에 간단하게 만들어본 페이지를 배포시켜서 사용을 해보았다.
배포한 이유는 빌드 파일로 확인을 해줘야 하기 때문이였는데
React 개발 모드에서는 React 자체의 에러 오버레이가 에러를 잡을 수 있다고 해서 설정해준 error fallback이 제대로 나오지 않아서 그렇다.
error fallback을 만들어주고
// errorFallBack.js
const ErrorFallBack = ({ error, resetErrorBoundary }) => {
return (
<div role="alert">
<p>에러가 발생했습니다</p>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>재시도</button>
</div>
);
};
export default ErrorFallBack;
라우터에서 사용을 해주었다.
RouterProvider 사용 시 Error Boundary
원래는
App.js
에서 사용을 해줬는데 제대로 동작하지 않았다
그 이유로는RouterProvider
와 관련된 에러 처리의 특성 때문일 수 있다고 한다.
App.js
에서 전역적으로ErrorBoundary
를 사용하면,
이는RouterProvider
밖에 있기 때문에,RouterProvider
내부 라우트에서 발생한 에러를 잡을 수 없다.
ErrorBoundary
는 자신의 자식 컴포넌트 트리에서 발생한 에러만 캐치할 수 있으며,
RouterProvider
가 내부적으로 관리하는 컴포넌트 트리는 그 범위에 포함되지 않는다.// route.js const router = createBrowserRouter([ { path: '/', element: <RootLayout />, children: [ { path: '', element: ( <div style={{ paddingTop: '100px' }}> <ErrorBoundary FallbackComponent={ErrorFallBack}> <MainPage queryKey={['popularData']} dataApi={popularApi} /> </ErrorBoundary> </div> ), },
그리고 일부러 에러를 발생시켜 테스트를 진행해봤다
처음에는 useEffect
를 사용하여 페이지가 마운트 되었을 때,
에러처리를 해주었는데 제대로 동작하지 않아 찾아보니
React의 useEffect
함수 내부에서 발생하는 에러는 비동기적으로 처리되기 때문에, ErrorBoundary
가 잡아내지 못하고, 대신 React 내부의 전역 에러 핸들러가 처리를 한다고 한다.
throw new Error('test error');
그래서 이렇게 동기적으로 에러처리를 해주었다.
추후 다른 토이프로젝트 및 프로젝트 진행 시 좀 더 다양하고 자세하게 사용하기 위해 조금 더 알아봐야겠다.