도입

서비스에서 메인 기능을 제외하고, UX를 위해서는 에러처리도 꽤 중요하다고 생각한다. 정말 탄탄하게 잘 만든 서비스와 무너지지 않게 구축된 서버가 아니고서야 사용자가 에러를 접할 가능성이 있다.

먼저 404는 페이지가 없는 것, 500은 당장 손쓸 수 없는 서버에러이므로, 각 페이지를 커스텀해서 보여줄 수 있도록 pages404.tsx , 500.tsx 을 생성했다.

기타 런타임 에러 처리도 필요하다. 렌더링 도중 에러가 발생할 경우 React 트리 전체가 언마운트되어, 유저는 빈 화면을 보게 되기 때문이다.

이를 위해 React에서는 Error Boundary 라는 것을 제공한다. Error Boundary 는 하위 컴포넌트 트리에서 발생한 에러를 잡아 선언적으로 처리할 수 있는 컴포넌트이다.

Error Boundary

Error Boundary는 자식 컴포넌트 트리 내의 자바스크립트 오류를 감지하고, 해당 오류를 기록하며, 충돌이 발생한 컴포넌트 트리를 대신하여 대체 UI를 표시하는 React 컴포넌트입니다. Error boundary의 하위 트리에 존재하는 렌더링 과정, 생명주기 메서드, 모든 생성자에 대하여 오류를 감지해냅니다.

클래스 컴포넌트에 static getDerivedStateFromError() 또는 componentDidCatch() 를 정의할 경우 해당 컴포넌트는 Error Boundary 가 된다.

React 공식홈페이지에서 제공하는 기본 ErrorBoundary 코드를 살펴보자.

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

  static getDerivedStateFromError(error) {
    // 다음 렌더링에서 폴백 UI가 보이도록 상태를 업데이트 합니다.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 에러 리포팅 서비스에 에러를 기록할 수도 있습니다.
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 폴백 UI를 커스텀하여 렌더링할 수 있습니다.
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

ErrorBoundary 가 포착하지 않는 에러에는 아래와 같은 것들이 있다.

이벤트 핸들러 → try/catch문을 이용해 포착 가능 비동기적 코드 (setTimeout, requestAnimationFrame 콜백) 서버 사이드 렌더링 Error Boundary 자체에서 발생하는 에러

클라이언트 에러

제공된 코드를 커스텀해서 ErrorBoundary 컴포넌트를 생성했다.