React에서 프로덕션 레디 에러 바운더리: 우아한 실패를 위한 패턴
발행: (2026년 4월 7일 PM 05:52 GMT+9)
5 분 소요
원문: Dev.to
Source: Dev.to
처리되지 않은 렌더링 오류는 전체 React 트리를 충돌시킵니다. 오류 경계는 손상을 차단합니다. 여기서는 프로덕션에서 이를 효과적으로 사용하는 방법을 소개합니다.
문제
// If UserCard throws, the entire page goes blank
function Dashboard() {
return (
<>
{/* if this throws, everything dies */}
</>
)
}
기본 오류 경계
오류 경계는 현재 클래스 컴포넌트여야 합니다:
import React, { Component, ReactNode } from 'react'
interface Props {
children: ReactNode
fallback?: ReactNode
}
interface State {
hasError: boolean
error: Error | null
}
class ErrorBoundary extends Component<Props, State> {
state: State = { hasError: false, error: null }
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error }
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error('ErrorBoundary caught:', error, info.componentStack)
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? <>Something went wrong</>
}
return this.props.children
}
}
react-error-boundary 사용하기
직접 구현하지 말고 검증된 라이브러리를 사용하세요:
npm install react-error-boundary
import { ErrorBoundary, FallbackProps } from 'react-error-boundary'
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
return (
<>
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</>
)
}
function Dashboard() {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
{/* Your dashboard content */}
</ErrorBoundary>
)
}
세분화된 경계
독립적인 섹션을 감싸세요 — 하나에서 발생한 오류가 다른 섹션에 영향을 주어서는 안 됩니다:
function Dashboard() {
return (
<>
<ErrorBoundary FallbackComponent={WidgetError}>
{/* Widget A */}
</ErrorBoundary>
<ErrorBoundary FallbackComponent={WidgetError}>
{/* Widget B */}
</ErrorBoundary>
<ErrorBoundary FallbackComponent={WidgetError}>
{/* Widget C */}
</ErrorBoundary>
</>
)
}
function WidgetError({ error, resetErrorBoundary }: FallbackProps) {
return (
<>
<p>Failed to load widget</p>
<button onClick={resetErrorBoundary}>Retry</button>
</>
)
}
오류 모니터링 서비스에 로깅하기
import * as Sentry from '@sentry/nextjs'
function onError(error: Error, info: { componentStack: string }) {
Sentry.captureException(error, {
extra: { componentStack: info.componentStack },
})
}
라우트 변경 시 리셋
import { useLocation } from 'react-router-dom'
import { ErrorBoundary } from 'react-error-boundary'
function App() {
const location = useLocation()
return (
<ErrorBoundary
onReset={() => {
// Reset logic when the route changes
}}
resetKeys={[location.pathname]}
>
{/* Your app routes */}
</ErrorBoundary>
)
}
Error Boundary가 잡지 못하는 오류
- 이벤트 핸들러 내부의 오류 (
try/catch를 핸들러 안에서 사용) - 비동기 코드에서 발생하는 오류 (
try/catch와 컴포넌트 상태로 처리) - SSR 중 발생하는 오류
- Boundary 컴포넌트 자체에서 발생하는 오류
// This WON’T be caught by an error boundary:
function Button() {
const handleClick = async () => {
try {
await submitForm() // async error — handle here
} catch (err) {
setError(err.message)
}
}
return <button onClick={handleClick}>Submit</button>
}
Next.js의 라우트‑레벨 경계
Next.js App Router에서는 error.tsx를 사용합니다:
// app/dashboard/error.tsx
'use client'
export default function DashboardError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<>
<h2>Dashboard failed to load</h2>
<button onClick={reset}>Try again</button>
</>
)
}
이 파일은 전체 /dashboard 라우트 세그먼트에 대한 내장 오류 경계 역할을 합니다.
Production Checklist
- Next.js의 라우트 수준
error.tsx파일 - 독립 위젯 주위의 세분화된 경계
- 오류 보고 연동 (Sentry / LogRocket)
- 의미 있는 폴백 UI (단순 흰 화면이 아님)
- 사용자가 복구할 수 있도록 리셋 버튼
- 이벤트 핸들러에서 비동기 오류 처리
The AI SaaS Starter Kit 은 Sentry가 통합되고, 라우트 수준 오류 경계가 설정되며, 모든 프로덕션 오류 처리 패턴이 사전 구성되어 제공됩니다. 일회성 $99 — 복제하고 바로 배포하세요.