React 16 업그레이드 후 componentDidCatch로 에러 경계 처리하기

문제 상황

프로덕션 환경에서 특정 컴포넌트의 렌더링 에러가 발생하면 전체 앱이 크래시되는 문제가 있었다. 사용자에게는 빈 화면만 보이고, Sentry에 에러 로그만 쌓이는 상황이 반복됐다.

React 16에서 새로 추가된 Error Boundary를 활용하면 이 문제를 해결할 수 있다는 걸 확인했다.

Error Boundary 구현

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    this.setState({ hasError: true });
    
    // Sentry 등 에러 로깅 서비스에 전송
    logErrorToService(error, info);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-fallback">
          <h2>문제가 발생했습니다</h2>
          <button onClick={() => window.location.reload()}>
            새로고침
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

적용 방법

중요한 컴포넌트 트리를 ErrorBoundary로 감쌌다. 전체 앱을 하나로 감쌀 수도 있지만, 페이지별로 나눠서 적용하는 게 더 좋았다.

<ErrorBoundary>
  <Dashboard />
</ErrorBoundary>

주의사항

  • 이벤트 핸들러 내부의 에러는 catch하지 못한다. 일반적인 try-catch를 사용해야 한다.
  • 비동기 코드(setTimeout, Promise)의 에러도 잡지 못한다.
  • ErrorBoundary 자체의 에러는 catch할 수 없다.

실제 적용 후 사용자에게 빈 화면 대신 에러 메시지와 복구 옵션을 제공할 수 있게 됐다. React 16의 가장 유용한 기능 중 하나라고 생각한다.