Error Boundary

React에서 하위 컴포넌트 트리에서 발생한 JavaScript 에러를 잡아 앱 전체가 crash되는 것을 방지하는 컴포넌트입니다.

핵심 개념

에러 없을 때
App → ErrorBoundary → ComponentA → ComponentB O

에러 발생 시 (ErrorBoundary 없음)
App → ComponentA → ComponentB → 앱 전체 흰 화면

에러 발생 시 (ErrorBoundary 있음)
App → ErrorBoundary → ComponentB
                  ↓
           Fallback UI 렌더링 O (나머지 앱은 정상)

기본 구현

Error Boundary는 클래스 컴포넌트로만 구현 가능합니다.

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

  // 에러 발생 시 state 업데이트
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // 에러 로깅
  componentDidCatch(error, errorInfo) {
    console.error("에러 발생:", error, errorInfo);
    // Sentry 등 에러 모니터링 서비스로 전송
  }

  render() {
    if (this.state.hasError) {
      return <h1>문제가 발생했습니다.</h1>;  // Fallback UI
    }
    return this.props.children;
  }
}

// 사용
function App() {
  return (
    <ErrorBoundary>
      <UserProfile />   {/* 에러 발생해도 앱 전체 crash 방지 */}
    </ErrorBoundary>
  );
}

부분적 적용 - 핵심 활용법

function App() {
  return (
    <div>
      <Header />  {/* ErrorBoundary 밖 → 항상 정상 렌더링 */}

      <ErrorBoundary fallback={<p>피드 로딩 실패</p>}>
        <Feed />        {/* 에러 발생 시 Fallback만 표시 */}
      </ErrorBoundary>

      <ErrorBoundary fallback={<p>추천 로딩 실패</p>}>
        <Recommendations />  {/* 독립적으로 에러 처리 */}
      </ErrorBoundary>
    </div>
  );
}

Error Boundary가 잡지 못하는 에러

// X 잡지 못하는 경우
1. 이벤트 핸들러
   <button onClick={() => { throw new Error() }}>  // try-catch로 직접 처리

2. 비동기 코드
   setTimeout(() => { throw new Error() }, 1000)   // try-catch로 직접 처리

3. SSR (서버사이드 렌더링)

4. Error Boundary 자체에서 발생한 에러

Error Boundary는 렌더링이 진행되는 하나의 연속된 콜 스택 흐름 안에서만 동작합니다. Promise나 setTimeout 같은 비동기 작업은 렌더링 콜스택이 모두 비워진 뒤 별도로 실행되기 때문에, 그 시점에 발생한 오류는 Error Boundary가 감지할 수 없습니다. 따라서 비동기 에러는 try-catch로 직접 처리하거나, setState로 에러 상태를 관리해 동기 렌더링 중에 에러를 다시 던지는 방식으로 우회해야 합니다.

react-error-boundary 라이브러리

함수형 컴포넌트에서 편리하게 사용할 수 있는 라이브러리입니다.

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div>
      <p>에러 발생: {error.message}</p>
      <button onClick={resetErrorBoundary}>다시 시도</button>  {/* 재시도 기능 */}
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary
      FallbackComponent={ErrorFallback}
      onError={(error) => console.error(error)}  // 에러 로깅
    >
      <UserProfile />
    </ErrorBoundary>
  );
}

getDerivedStateFromError vs componentDidCatch

메서드호출 시점용도
getDerivedStateFromError렌더링 중Fallback UI 표시 (state 업데이트)
componentDidCatch커밋 후에러 로깅, 모니터링 서비스 전송

Error Boundary는 앱의 일부가 실패해도 나머지는 정상 동작하도록 격리하는 것이 핵심입니다. 중요도에 따라 컴포넌트 단위로 세분화해서 적용하는 것이 좋습니다.

CSLOG에서 보기