React Error Boundary란 무엇이며 어떤 오류를 처리할 수 있나요?
답변 포인트
렌더링 중 발생한 오류를 하위 컴포넌트 트리 단위로 격리하는 기능입니다.
정답 및 해설
빠른 요약
Error Boundary는 하위 컴포넌트 렌더링 중 발생한 오류를 잡아 대체 UI를 보여주는 React 기능입니다. 잡을 수 있는 오류는 하위 컴포넌트 렌더링, 생명주기 메서드, constructor에서 발생한 오류입니다.
Error Boundary는 하위 컴포넌트 트리에서 렌더링 중 발생한 오류를 잡아, 전체 앱이 깨지는 대신 대체 UI를 보여주는 React 기능입니다.
왜 필요한가요?
React 컴포넌트 렌더링 중 예외가 발생하면 해당 컴포넌트 트리 전체가 언마운트될 수 있습니다. Error Boundary를 두면 오류가 난 영역만 격리하고 사용자에게 복구 가능한 화면을 보여줄 수 있습니다.
<ErrorBoundary>
<ProfilePage />
</ErrorBoundary>ProfilePage 내부 렌더링에서 문제가 생겨도 앱 전체가 흰 화면이 되는 것을 막을 수 있습니다.
클래스 컴포넌트로 구현
React의 Error Boundary는 전통적으로 클래스 컴포넌트의 생명주기 메서드로 구현합니다.
type State = { hasError: boolean };
class ErrorBoundary extends React.Component<React.PropsWithChildren, State> {
state: State = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error(error, info);
}
render() {
if (this.state.hasError) {
return <p>문제가 발생했습니다. 잠시 후 다시 시도해주세요.</p>;
}
return this.props.children;
}
}처리할 수 있는 오류
Error Boundary가 잡을 수 있는 오류:
- 하위 컴포넌트의 렌더링 중 오류
- 생명주기 메서드에서 발생한 오류
- 클래스 컴포넌트 constructor에서 발생한 오류
잡을 수 없는 오류:
- 이벤트 핸들러 내부 오류
- 비동기 코드의 오류
- 서버 사이드 렌더링 중 오류
- Error Boundary 자신이 던진 오류
이벤트 핸들러 오류 처리
이벤트 핸들러는 Error Boundary가 잡지 않으므로 직접 try/catch로 처리합니다.
function SaveButton() {
const handleClick = async () => {
try {
await save();
} catch (error) {
alert("저장에 실패했습니다.");
}
};
return <button onClick={handleClick}>저장</button>;
}어디에 배치하면 좋나요?
Error Boundary는 앱 전체를 한 번 감싸는 것보다, 장애 격리가 필요한 영역별로 두는 것이 좋습니다.
<Layout>
<ErrorBoundary>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary>
<MainContent />
</ErrorBoundary>
</Layout>이렇게 하면 Sidebar 오류가 MainContent까지 망가뜨리지 않습니다.
정리
Error Boundary는 렌더링 오류를 사용자 경험 수준에서 격리하는 장치입니다. 다만 이벤트 핸들러나 비동기 오류까지 자동으로 잡아주는 전역 예외 처리기가 아니므로, 오류 발생 위치에 따라 별도 처리 전략이 필요합니다.
Error Boundary가 필요한 이유
React 렌더링 중 예외가 발생하면 해당 트리 전체가 깨질 수 있습니다. Error Boundary는 특정 하위 UI에서 발생한 렌더링 오류를 잡아 대체 UI를 보여주는 안전망입니다.
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
reportError(error, info.componentStack);
}
render() {
if (this.state.hasError) return <Fallback />;
return this.props.children;
}
}잡을 수 있는 오류와 잡지 못하는 오류
| 구분 | 처리 여부 |
|---|---|
| 렌더링 중 오류 | 잡을 수 있음 |
| 생명주기 메서드 오류 | 잡을 수 있음 |
| 하위 컴포넌트 constructor 오류 | 잡을 수 있음 |
| 이벤트 핸들러 오류 | 직접 try/catch 필요 |
| 비동기 콜백 오류 | 직접 처리 필요 |
| 서버 사이드 렌더링 오류 | 일반 Error Boundary로는 불가 |
배치 전략
전체 앱을 하나의 Error Boundary로만 감싸면 작은 위젯 오류도 전체 fallback으로 바뀝니다. 라우트 단위, 주요 패널 단위, 외부 위젯 단위로 나누면 장애 범위를 줄일 수 있습니다.