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 응답 검증은 별도로 개선했다.

React 프로젝트에 ErrorBoundary 적용하기