React 애플리케이션의 에러 처리 전략: ErrorBoundary vs ErrorPage
React 애플리케이션에서 에러를 처리하는 방법은 크게 두 가지가 있습니다: ErrorBoundary와 React Router의 ErrorPage입니다. 각각의 사용 사례와 차이점을 알아보겠습니다.
1. ErrorBoundary
ErrorBoundary는 React 컴포넌트 트리 내에서 발생하는 JavaScript 에러를 캐치하고 처리하는 React 컴포넌트입니다.
ErrorBoundary가 처리하는 에러:
- 컴포넌트 렌더링 중 발생하는 에러
- 이벤트 핸들러에서 throw된 에러
- React Query의 throwOnError가 true일 때 발생하는 쿼리 에러
ErrorBoundary 구현 예시:
import { Component, ErrorInfo, ReactNode } from 'react';
import { NetworkError } from '../errors';
interface ErrorBoundaryState {
hasError: boolean;
errorInfo?: {
message: string;
code?: number;
};
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = {
hasError: false,
errorInfo: undefined,
};
}
public static getDerivedStateFromError(error: Error): ErrorBoundaryState {
if (error instanceof NetworkError) {
return {
hasError: true,
errorInfo: {
message: error.message,
code: error.code,
},
};
}
return {
hasError: true,
errorInfo: {
message: '예상치 못한 오류가 발생했습니다.',
},
};
}
public render() {
if (this.state.hasError) {
return (
<div className="error-container">
<h2>문제가 발생했습니다</h2>
<p>{this.state.errorInfo?.message}</p>
<button onClick={() => window.location.reload()}>
다시 시도
</button>
</div>
);
}
return this.props.children;
}
}
사용 예시:
// React Query에서 에러 발생 시
const query = useQuery({
queryKey: ['key'],
queryFn: async () => {
throw new NetworkError({ code: 500 }); // ErrorBoundary가 캐치
},
throwOnError: true
});
// 컴포넌트에서 직접 에러 throw
if (someError) {
throw new Error('Component Error'); // ErrorBoundary가 캐치
}
2. ErrorPage (React Router)
React Router의 errorElement는 라우팅 관련 에러를 처리하는 데 사용됩니다.
ErrorPage가 처리하는 에러:
- 라우팅 관련 에러 (404 등)
- loader나 action에서 throw된 에러
- 잘못된 URL 접근
라우터 설정 예시:
const router = createBrowserRouter([
{
path: '/',
element: <RootPage />,
errorElement: <ErrorPage />, // 라우팅 에러 처리
loader: async () => {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error('Failed to fetch'); // ErrorPage로 이동
}
return response.json();
},
children: [
// ... 라우트 설정
]
}
]);
에러 처리 전략
1. ErrorBoundary 사용
- 컴포넌트 렌더링 관련 에러
- React Query 에러 (throwOnError: true)
- UI 관련 예외 상황
2. ErrorPage 사용
- 라우팅 관련 에러
- API 로딩 실패
- 인증/인가 관련 에러
3. 함께 사용하기
createRoot(document.getElementById('root') as HTMLElement).render(
<ErrorBoundary>
<RouterProvider router={router} />
</ErrorBoundary>
);
이렇게 구성하면:
- ErrorBoundary: 컴포넌트 레벨의 에러 처리
- ErrorPage: 라우팅/데이터 로딩 관련 에러 처리
- 계층적 에러 처리 가능
결론
- ErrorBoundary는 컴포넌트 트리 내의 JavaScript 에러를 처리
- ErrorPage는 라우팅과 데이터 로딩 관련 에러를 처리
- 두 가지 방식을 적절히 조합하여 사용하면 더 견고한 에러 처리 가능
같은 API 호출의 다른 에러 처리 경로
1. loader에서 호출 시 → ErrorPage
// route 정의
{
path: '/articles',
element: <ArticlesPage />,
loader: async () => {
const response = await fetch('/api/articles');
if (!response.ok) {
throw new Error('Failed to fetch'); // ErrorPage로 이동
}
return response.json();
}
}
2. 컴포넌트 내부에서 호출 시 → ErrorBoundary
const ArticlesPage = () => {
const query = useQuery({
queryKey: ['articles'],
queryFn: async () => {
const response = await fetch('/api/articles');
if (!response.ok) {
throw new Error('Failed to fetch'); // ErrorBoundary로 이동
}
return response.json();
},
throwOnError: true
});
return <div>{/* ... */}</div>;
};
차이가 발생하는 이유
- 로더(Loader)의 에러
- 컴포넌트가 렌더링되기 전에 발생
- React Router가 처리
- 라우팅 수준의 에러로 간주
- ErrorPage로 이동
- 컴포넌트 내부의 에러
- 컴포넌트 렌더링 중에 발생
- React의 에러 경계가 처리
- UI 수준의 에러로 간주
- ErrorBoundary가 캐치
'개발 > 기록' 카테고리의 다른 글
Netlify로 배포할 때 편한 점 (0) | 2024.12.04 |
---|---|
slow 4g 환경에서 FCP, LCP 측정 비교 (0) | 2024.12.03 |
null과 undefined 차이 (2) | 2024.11.21 |
React Query - isPending vs isFetching (0) | 2024.11.15 |
reactquery query key undefined 제거하기 (0) | 2024.11.10 |