React 프로젝트에 ErrorBoundary 적용하기
문제 상황
재택근무 중 슬랙으로 긴급 알림이 왔다. 특정 페이지에서 API 응답 데이터 구조가 예상과 달라 Cannot read property 'map' of undefined 에러가 발생하며 전체 화면이 백지로 표시되는 문제였다.
// 문제가 된 코드
const ProductList = ({ products }) => {
return (
<div>
{products.map(product => ( // products가 undefined일 때 에러
<ProductCard key={product.id} {...product} />
))}
</div>
)
}
ErrorBoundary 도입
React 16부터 제공하는 ErrorBoundary를 사용해 에러를 컴포넌트 단위로 격리하기로 했다.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
// Sentry로 에러 로깅
console.error('Error caught:', error, errorInfo)
}
render() {
if (this.state.hasError) {
return (
<div className="error-fallback">
<h2>일시적인 오류가 발생했습니다</h2>
<button onClick={() => window.location.reload()}>
새로고침
</button>
</div>
)
}
return this.props.children
}
}
적용 전략
페이지 단위로 ErrorBoundary를 감싸서 한 섹션의 에러가 전체 앱을 중단시키지 않도록 했다.
function App() {
return (
<Router>
<Header />
<ErrorBoundary>
<Switch>
<Route path="/products" component={ProductPage} />
<Route path="/cart" component={CartPage} />
</Switch>
</ErrorBoundary>
</Router>
)
}
결과
- 에러 발생 시 전체 화면이 깨지지 않고 fallback UI 표시
- 사용자에게 새로고침 옵션 제공
- 에러 로그를 통해 문제 파악 시간 단축
다만 ErrorBoundary는 이벤트 핸들러 내부 에러는 잡지 못하므로 try-catch와 병행해야 한다는 점을 알게 됐다. 근본 원인인 API 응답 검증은 별도로 개선했다.