Theme:

블로그: 화면이 하얗게 뜨면 끝이다에 대해 "왜?"라고 물으면 답할 수 있으신가요?

\n\n> 블로그: 화면이 하얗게 뜨면 끝이다에 대해 "왜?"라고 물으면 답할 수 있으신가요?\n프론트엔드에서 제일 끔찍한 상황이 뭘까요. 저는 하얀 화면 이라고 생각합니다.

에러 메시지라도 뜨면 뭐가 문제인지라도 짐작이 가는데, 하얀 화면은 아무 정보가 없습니다. 사용자 입장에서는 그냥 "고장났다"고 생각하고 나갑니다. 개발자 입장에서는 콘솔 열어봐야 뭔지 알 수 있고요.

React에서 컴포넌트 렌더링 중 에러가 발생하면, 기본적으로 전체 컴포넌트 트리가 언마운트 됩니다. 하나의 컴포넌트에서 터진 에러가 전체 앱을 죽이는 거죠.

이걸 방지하는 게 ErrorBoundary 입니다.


ErrorBoundary란

ErrorBoundary는 하위 컴포넌트에서 발생한 에러를 잡아서 대체 UI를 보여주는 클래스 컴포넌트입니다. try-catch의 컴포넌트 버전이라고 생각하면 됩니다.

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

    static getDerivedStateFromError(error) {
        return { hasError: true, error };
    }

    componentDidCatch(error, errorInfo) {
        console.error('ErrorBoundary caught:', error, errorInfo);
    }

    render() {
        if (this.state.hasError) {
            return this.props.fallback || <DefaultErrorUI error={this.state.error} />;
        }
        return this.props.children;
    }
}

getDerivedStateFromError에서 에러를 감지하고, componentDidCatch에서 로깅합니다. hasError가 true면 fallback UI를 렌더링하고, 아니면 정상적으로 children을 렌더링합니다.

왜 클래스 컴포넌트인가

2026년에 클래스 컴포넌트를 쓴다고? 네. getDerivedStateFromErrorcomponentDidCatch는 아직 Hook으로 제공되지 않습니다. ErrorBoundary는 클래스로 작성해야 합니다. 이건 React 팀의 의도적인 결정이라고 합니다.


에러 복구 UI

하얀 화면 대신 보여줄 UI를 만들었습니다. 핵심은 사용자가 복구할 수 있는 수단을 제공 하는 겁니다.

JSX
const DefaultErrorUI = ({ error, resetError }) => {
    return (
        <div className="error-screen">
            <div className="error-content">
                <h1>문제가 발생했습니다</h1>
                <p className="error-message">
                    {error?.message || '알 수 없는 오류'}
                </p>

                <div className="error-actions">
                    <button onClick={resetError}>
                        다시 시도
                    </button>
                    <button onClick={() => window.location.href = '/'}>
                        홈으로 이동
                    </button>
                </div>
            </div>
        </div>
    );
};

단순히 "에러가 발생했습니다"만 보여주면 사용자는 뭘 해야 할지 모릅니다. 최소한 "다시 시도"와 "홈으로" 버튼은 있어야 합니다.


적용 위치

ErrorBoundary를 어디에 두느냐에 따라 에러의 영향 범위가 달라집니다.

최상위: 앱 전체 감싸기

JSX
function App() {
    return (
        <ErrorBoundary>
            <Suspense fallback={/* ... */}>
                <Routes>
                    {/* ... */}
                </Routes>
            </Suspense>
        </ErrorBoundary>
    );
}

어디서 에러가 터지든 최소한 하얀 화면은 안 뜹니다. 가장 기본적인 안전장치입니다.

부분적: 위험한 영역만 감싸기

JSX
<article>
    <ErrorBoundary fallback={<p>글을 불러오지 못했습니다.</p>}>
        <PostDetailBody post={post} />
    </ErrorBoundary>

    {/* 본문 에러가 나도 댓글은 살아있음 */}
    <PostDetailComment />
</article>

마크다운 렌더링 중 에러가 나도 댓글 영역은 정상 동작합니다. 에러가 터진 영역만 fallback으로 대체되고 나머지는 멀쩡합니다.

이 블로그에서는 두 가지를 모두 적용했습니다. 최상위에 하나, 마크다운 렌더링 부분에 하나.


ErrorBoundary가 못 잡는 것들

ErrorBoundary가 만능은 아닙니다. 다음은 잡지 못합니다.

잡는 에러못 잡는 에러
렌더링 중 에러이벤트 핸들러 내부 에러
생명주기 메서드 에러비동기 코드 (setTimeout, Promise)
하위 컴포넌트 에러서버 사이드 렌더링 에러

이벤트 핸들러에서 터지는 에러는 일반 try-catch로 잡아야 하고, 비동기 에러는 Promise의 catch로 처리해야 합니다.

JAVASCRIPT
// 이벤트 핸들러 — ErrorBoundary가 못 잡음
const handleClick = () => {
    try {
        riskyOperation();
    } catch (error) {
        // 직접 처리
        setError(error);
    }
};

에러 리셋

ErrorBoundary에 갇히면 사용자가 "다시 시도"를 눌러도 상태가 리셋되지 않으면 같은 에러가 반복됩니다. 리셋 기능을 추가합니다.

JSX
class ErrorBoundary extends React.Component {
    resetError = () => {
        this.setState({ hasError: false, error: null });
    };

    render() {
        if (this.state.hasError) {
            return <DefaultErrorUI
                error={this.state.error}
                resetError={this.resetError}
            />;
        }
        return this.props.children;
    }
}

"다시 시도" 버튼을 누르면 hasError가 false로 돌아가고, children이 다시 렌더링됩니다. 일시적인 에러였다면 이걸로 복구가 됩니다.


개발 중에는 일부러 터뜨려보기

ErrorBoundary가 제대로 동작하는지 확인하려면, 의도적으로 에러를 만들어봐야 합니다.

JSX
const BrokenComponent = () => {
    throw new Error('테스트 에러');
    return <div>이건 안 보임</div>;
};

// 사용
<ErrorBoundary>
    <BrokenComponent />
</ErrorBoundary>

프로덕션에 나가기 전에 fallback UI가 잘 뜨는지, 복구 버튼이 동작하는지 꼭 확인해보세요.


마무리

ErrorBoundary는 보험 같은 겁니다. 없어도 대부분의 경우 문제없이 돌아가지만, 한 번 터지면 그때부터는 다릅니다.

특히 블로그처럼 사용자가 개발자가 아닌 경우, 하얀 화면은 "이 사이트 고장났네" 하고 다시 안 옵니다. 최소한 "문제가 생겼는데, 이렇게 하면 돼요"라고 안내해주는 건 기본이라고 생각합니다.

이 글을 끝으로 블로그 만들기 시리즈를 마칩니다. 배포부터 마크다운 렌더링, 터미널, PWA, 분석까지 — 서버 없이 이만큼 만들 수 있다는 걸 보여드리고 싶었습니다. 읽어주셔서 감사합니다.

댓글 로딩 중...