본문 바로가기
C.W.K.
Stream
Lesson 03 of 07 · published

오류 경계 — 여전히 쓰는 유일한 클래스

~11 min · error-boundary, errors, fallback

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
오류 경계는 렌더링 트리의 try/catch 역할을 해. 자식에서 난 오류를 잡고 해당 영역만 대체 UI로 바꾸는 방법을 익혀.

오류 경계가 잡는 것

오류 경계는 자식 컴포넌트가 렌더링 중에 던진 오류를 잡아. 이벤트 핸들러의 오류, setTimeout이나 일반 프로미스 안에서 처리되지 않은 오류, 경계 자체의 오류, 서버 렌더링 오류는 잡지 않아. 각각 발생한 위치나 상위 계층에서 처리해야 해.

Suspense가 기다림을 맡고 use()가 데이터를 읽는 구조에서는 오류 경계가 실패 경로를 담당해. 로딩·오류·성공을 서로 다른 책임으로 나누는 셈이야.

클래스 컴포넌트의 두 메서드

오류 경계에는 getDerivedStateFromErrorcomponentDidCatch가 필요해. 첫 번째는 자식이 오류를 던졌을 때 대체 UI를 보여 줄 상태를 만들고, 두 번째는 오류와 컴포넌트 정보를 추적 서비스에 기록할 자리를 제공해.

react-error-boundary

react-error-boundary는 이 클래스 패턴을 재사용 가능한 <ErrorBoundary>로 제공해. 이벤트나 비동기 콜백처럼 렌더링 밖에서 생긴 오류를 경계로 보내는 useErrorBoundary도 함께 제공하므로 대부분의 앱은 직접 클래스를 반복해서 만들 필요가 없어.

다시 시도하기

경계가 오류 상태에 들어가면 명시적으로 초기화할 때까지 대체 UI를 유지해. 라이브러리의 resetErrorBoundary를 다시 시도 버튼에 연결하면 해당 영역을 다시 렌더링할 수 있어.

독립적으로 보여 주는 기능마다 경계를 둬. 앱 전체를 경계 하나로 감싸면 작은 오류에도 전체 화면이 사라져. 사이드바, 메인 패널, 설정 대화상자처럼 서로 독립된 영역에 경계를 두면 한 기능이 실패해도 나머지는 계속 쓸 수 있어.

오류 경계가 잡는 범위

자식이 렌더링되는 동안 던진 오류와 생명주기 오류는 가장 가까운 경계가 잡아. 이벤트 핸들러와 setTimeout 안의 오류, 서버 렌더링 자체의 오류는 자동으로 잡지 않아. 이벤트에서 경계 UI로 보내려면 react-error-boundary의 showBoundary 같은 명시적 경로를 사용해.

React core의 경계는 아직 클래스야

getDerivedStateFromError로 대체 UI 상태를 만들고 componentDidCatch에서 오류를 기록해. 앱 코드에서 직접 클래스를 반복하기 싫다면 react-error-boundary의 ErrorBoundary와 reset 기능을 사용할 수 있어.

Reset 버튼은 원인이 된 state나 query도 함께 초기화해야 해. 같은 잘못된 값을 둔 채 경계만 reset하면 바로 다시 오류가 발생해.

Code

직접 만드는 최소 오류 경계 class·tsx
import { Component, type ReactNode } from "react";

type Props = {
  fallback: (error: Error, reset: () => void) => ReactNode;
  children: ReactNode;
};
type State = { error: Error | null };

export class ErrorBoundary extends Component<Props, State> {
  state: State = { error: null };

  static getDerivedStateFromError(error: Error): State {
    return { error };
  }

  componentDidCatch(error: Error, info: React.ErrorInfo) {
    // 본인 에러 트래커에 리포트.
    console.error("ErrorBoundary caught:", error, info);
  }

  reset = () => this.setState({ error: null });

  render() {
    if (this.state.error) {
      return this.props.fallback(this.state.error, this.reset);
    }
    return this.props.children;
  }
}
react-error-boundary: 다듬은 버전·tsx
import { ErrorBoundary } from "react-error-boundary";
import { Suspense } from "react";

function Fallback({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void }) {
  return (
    <div role="alert" className="p-4 rounded-card bg-bg-elevated">
      <p className="text-danger font-medium">Something went wrong</p>
      <p className="text-muted text-sm mt-1">{error.message}</p>
      <button
        onClick={resetErrorBoundary}
        className="mt-3 px-3 py-1 rounded bg-brand text-bg"
      >
        Try again
      </button>
    </div>
  );
}

// ErrorBoundary를 Suspense 바깥에 두면 안쪽의 렌더링 오류를 잡을 수 있어.
function App() {
  return (
    <ErrorBoundary FallbackComponent={Fallback}>
      <Suspense fallback={<p>Loading…</p>}>
        <Page />
      </Suspense>
    </ErrorBoundary>
  );
}

External links

Exercise

react-error-boundary를 설치하고 앱의 콘텐츠를 친근한 fallback과 reset 버튼이 있는 ErrorBoundary로 감싸. 렌더링 중 오류를 던져 fallback과 복구를 확인한 뒤 click handler에서도 오류를 내 경계가 자동으로 잡지 않는 차이를 관찰해.
Hint
이벤트 handler의 오류를 같은 경계로 보내려면 useErrorBoundary().showBoundary(error)를 호출할 수 있어. 사용자가 고칠 수 있는 오류라면 local state로 표시하는 선택도 비교해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.