BioPlayground

🧬
목록으로

프론트엔드 예외처리 — 가장 중요한데 가장 안 하는 것

프론트엔드에서 예외처리가 왜 중요한지, 빈 화면을 방지하는 Error Boundary와 에러 핸들링 패턴을 설명합니다.

중급
|
5
|
검증 완료 (2026-07)
진행률0/36 (0%)

프론트엔드 예외처리 — 가장 중요한데 가장 안 하는 것

이 토픽을 마치면

프론트엔드에서 예외처리가 왜 빠지기 쉬운지, 그리고 어떻게 하면 빈 화면 대신 의미 있는 피드백을 줄 수 있는지 알게 됩니다.


백엔드는 에러가 나면 500이 뜹니다

백엔드에서 에러가 나면 서버가 500 응답을 보냅니다. 로그에 스택 트레이스가 남습니다. 개발자가 로그를 보고 수정합니다. 사용자는 "잠시 후 다시 시도해주세요" 메시지를 봅니다.

프론트엔드에서 에러가 나면? 화면이 하얗게 됩니다. 아무것도 안 뜹니다. 사용자는 새로고침을 해도 같은 하얀 화면을 봅니다. 에러 메시지도 없습니다.

왜 이렇게 되나면, JavaScript에서 처리되지 않은 에러가 발생하면 해당 컴포넌트 트리 전체가 죽기 때문입니다. React에서는 한 컴포넌트의 에러가 전체 앱을 무너뜨립니다.


왜 안 하는가

예외처리를 안 하는 이유는 단순합니다: "일단 되니까."

개발 중에는 데이터가 항상 있고, 네트워크가 항상 되고, 사용자가 정상적인 입력만 합니다. 에러가 안 나니까 에러 처리를 안 합니다.

하지만 실제 사용자 환경은 다릅니다:

  • API가 503을 반환합니다
  • 데이터가 null입니다
  • 네트워크가 끊겼다 붙었다 합니다
  • 브라우저 확장이 DOM을 건드립니다

이 중 하나라도 발생하면 TypeError: Cannot read properties of undefined가 터지고, 하얀 화면이 됩니다.


기본: API 호출에 try-catch

가장 흔한 에러 지점은 API 호출입니다:

javascript
// 위험한 코드
const res = await fetch("/api/users");
const data = await res.json();
setUsers(data.users);  // data가 null이면 터짐

// 안전한 코드
try {
  const res = await fetch("/api/users");
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();
  setUsers(data.users ?? []);
} catch (err) {
  setError("사용자 목록을 불러올 수 없습니다.");
}

핵심은 에러가 났을 때 사용자에게 뭘 보여줄 것인가입니다. 하얀 화면 대신 "다시 시도해주세요" 버튼이라도 있어야 합니다.


React Error Boundary

API 호출은 try-catch로 잡을 수 있지만, 렌더링 중에 발생하는 에러는 잡을 수 없습니다. 컴포넌트가 그려지다가 에러가 나면 React 전체가 멈춥니다.

이걸 잡아주는 게 Error Boundary입니다:

javascript
class ErrorBoundary extends React.Component {
  state = { hasError: false };

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

  render() {
    if (this.state.hasError) {
      return <p>문제가 발생했습니다. 새로고침해 주세요.</p>;
    }
    return this.props.children;
  }
}
javascript
<ErrorBoundary>
  <UserProfile />
</ErrorBoundary>

UserProfile에서 에러가 나면 전체 앱이 죽는 대신, "문제가 발생했습니다" 메시지가 표시됩니다. 앱의 나머지 부분은 정상 동작합니다.

Error Boundary를 페이지 단위로 감싸면, 한 페이지의 에러가 다른 페이지에 영향을 주지 않습니다.


로딩과 빈 상태도 예외입니다

에러만이 예외가 아닙니다. 데이터가 아직 안 왔거나 비어있는 경우도 처리해야 합니다:

javascript
function UserList({ users }) {
  if (users === undefined) return <Spinner />;      // 로딩 중
  if (users.length === 0) return <p>사용자가 없습니다.</p>;  // 빈 상태
  return users.map(u => <UserCard key={u.id} user={u} />);
}

로딩 중(Loading), 빈 상태(Empty), 에러(Error), 정상(Success) — 이 네 가지 상태를 모두 처리하는 게 프론트엔드 예외처리의 전부입니다.

이걸 무시하면 사용자는 빈 화면을 보면서 "로딩 중인 건지, 데이터가 없는 건지, 에러인 건지" 구분할 수 없습니다.


실무 체크리스트

프론트엔드 예외처리를 점검할 때 이걸 물어보면 됩니다:

  • API가 실패하면 사용자에게 뭐가 보이나?
  • 데이터가 null이면 화면이 죽지 않나?
  • 네트워크가 끊기면 어떻게 되나?
  • 로딩 중에는 뭐가 보이나?
  • 데이터가 비어있으면 뭐가 보이나?

이 질문에 "하얀 화면" 또는 "모르겠다"가 답이면, 예외처리가 빠져있는 것입니다.


핵심

프론트엔드에서 처리되지 않은 에러는 **하얀 화면(White Screen of Death)**을 만듭니다. Error Boundary는 렌더링 에러를 잡아 앱 전체가 죽는 것을 방지합니다. 로딩/빈 상태/에러/정상 — 네 가지 상태를 모두 처리하는 것이 핵심입니다.