ErrorBoundary
이 컴포넌트는 children에 에러가 발생하면 제어할 수 있습니다.
비교
@suspensive/react의 <ErrorBoundary/>는 React의 클래스 기반 에러 경계와 인기 있는 react-error-boundary 및 @sentry/react와 같은 에러 경계 라이브러리에 대한 선언적이고 기능이 풍부한 대안을 제공합니다.
| @suspensive/react | react-error-boundary | @sentry/react | DIY (Class Component) | ||
|---|---|---|---|---|---|
| Error Boundary | shouldCatch | ✓ | ✗ | ✗ | ✗ |
| ErrorBoundaryGroup | ✓ | ✗ | ✗ | ✗ | |
| useErrorBoundaryFallbackProps | ✓ | ✗ | ✗ | ✗ | |
| Safe fallback error propagation | ✓ To parent | ✗ Recursive | ✗ Recursive | ✗ | |
| TypeScript error type inference | ✓ Via shouldCatch | ✗ | ✗ | ✗ | |
| useErrorBoundary hook | ✓ | ✓ | ✗ | ✗ | |
| Fallback UI with error & reset | ✓ | ✓ | ✓ | ✗ | |
| resetKeys | ✓ | ✓ | ✗ | ✗ | |
| onReset callback | ✓ | ✓ | ✓ | ✗ | |
| onError callback | ✓ | ✓ | ✓ | ✗ | |
| HOC support | ✓ ErrorBoundary.with | ✓ withErrorBoundary | ✓ withErrorBoundary | ✗ | |
| Declarative API | ✓ | ✓ | ✓ | ✗ | |
| Async Rendering | SSR-safe Suspense (clientOnly) | ✓ | ✗ | ✗ | ✗ |
| Flash-of-loading prevention (Delay) | ✓ | ✗ | ✗ | ✗ | |
| Global default fallbacks (DefaultPropsProvider) | ✓ | ✗ | ✗ | ✗ | |
| Declarative data fetching (SuspenseQuery) | ✓ | ✗ | ✗ | ✗ | |
| Client-only rendering (ClientOnly) | ✓ | ✗ | ✗ | ✗ |
@suspensive/react
import { ErrorBoundary } from '@suspensive/react'
const SuspensiveExample = () => (
<ErrorBoundary
fallback={({ error, reset }) => (
<div>
<button onClick={reset}>리셋</button>
{error.message}
</div>
)}
>
<YourComponent />
</ErrorBoundary>
)@suspensive/react의 주요 장점
-
shouldCatch를 통한 고급 에러 필터링: 다른 솔루션과 달리,
@suspensive/react는 boolean, ErrorConstructor 또는 콜백 매처를 사용하여 특정 에러를 조건부로 캐치할 수 있습니다. 이를 통해 부모와 자식 ErrorBoundary가 서로 다른 에러 타입을 처리할 수 있는 정교한 에러 처리 전략을 구현할 수 있습니다. -
적절한 Fallback 에러 처리:
react-error-boundary와 달리, fallback 컴포넌트에서 발생한 에러는 같은 경계에서 재귀적으로 캐치되는 대신 부모 ErrorBoundary로 전달됩니다. 이를 통해 무한 fallback 루프를 방지하고 더 예측 가능한 에러 처리 동작을 제공합니다. 자세히 알아보기 -
useErrorBoundaryFallbackProps: fallback 컴포넌트에서 prop drilling을 제거하고 훅을 통해
error와reset에 직접 접근할 수 있어, 깊게 중첩된 fallback UI를 훨씬 깔끔하게 만들 수 있습니다. -
ErrorBoundaryGroup: 여러 ErrorBoundary를 함께 관리하고 리셋할 수 있으며, 조정된 리셋 동작이 필요한 여러 에러 경계가 있는 복잡한 UI에 완벽합니다.
-
더 나은 TypeScript 지원: shouldCatch 구성을 기반으로 에러 타입에 대한 고급 타입 추론을 제공하여 더 나은 자동 완성과 타입 안정성을 제공합니다.
-
클래스 컴포넌트 불필요: 네이티브 React 에러 경계와 달리, 클래스 컴포넌트를 작성하지 않고도 완전히 선언적인 함수 컴포넌트 기반 접근 방식을 사용할 수 있습니다.
마이그레이션 가이드
react-error-boundary에서
react-error-boundary를 사용하고 있다면, @suspensive/react로 마이그레이션하는 것은 간단합니다:
// react-error-boundary
import { ErrorBoundary } from 'react-error-boundary'
const ReactErrorBoundaryExample = () => (
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<div>
<button onClick={resetErrorBoundary}>리셋</button>
{error.message}
</div>
)}
onReset={() => console.log('reset')}
>
<YourComponent />
</ErrorBoundary>
)
// @suspensive/react - 동일한 기능
import { ErrorBoundary } from '@suspensive/react'
const SuspensiveExample = () => (
<ErrorBoundary
fallback={({ error, reset }) => (
<div>
<button onClick={reset}>리셋</button>
{error.message}
</div>
)}
onReset={() => console.log('reset')}
>
<YourComponent />
</ErrorBoundary>
)주요 API 차이점:
fallback,fallbackRender,FallbackComponent→fallbackresetErrorBoundary→reset(fallback props에서)
props.fallback
<ErrorBoundary/>의 children에 error가 발생하면 error는 잡히고 fallback이 렌더링됩니다.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect } from 'react'
const Example = () => (
<ErrorBoundary
fallback={(props) => (
<>
<button onClick={props.reset}>Try again</button>
{props.error.message}
</>
)}
>
<ErrorAfter2s />
</ErrorBoundary>
)<ErrorBoundary/>의 fallback으로 전달할 컴포넌트 정의하기
ErrorBoundaryFallbackProps
<ErrorBoundary/>의 fallback으로 컴포넌트를 전달하고 싶다면 ErrorBoundaryFallbackProps 타입을 활용해 쉽게 컴포넌트를 선언할 수 있습니다.
import type { ErrorBoundaryFallbackProps } from '@suspensive/react'
const ErrorBoundaryFallback = ({
reset,
error,
}: ErrorBoundaryFallbackProps) => (
<>
<button onClick={reset}>reset</button>
{error.message}
</>
)
const Example = () => (
<ErrorBoundary fallback={ErrorBoundaryFallback}>
<ErrorAfter2s />
</ErrorBoundary>
)props.resetKeys
<ErrorBoundary/>의 fallback 외부에 있는 컴포넌트가 <ErrorBoundary/>를 reset하려면 resetKeys배열에 resetKey를 할당하면 됩니다. resetKeys는 배열의 하나 이상의 요소가 변경된 경우에만 작동합니다. useEffect의 종속성 배열이 작동하는 방식과 같이 resetKeys로 매 렌더링마다 새 배열을 주입하는 것을 걱정할 필요도 없습니다.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect } from 'react'
const Example = () => {
const [resetKey, setResetKey] = useState(0)
return (
<>
<button onClick={() => setResetKey((prev) => prev + 1)}>Try again</button>
<ErrorBoundary
resetKeys={[resetKey]}
fallback={(props) => <>{props.error.message}</>}
>
<ErrorAfter2s />
</ErrorBoundary>
</>
)
}props.onReset
<ErrorBoundary/>가 reset할 때 먼저 호출되는 callback입니다. @tanstack/react-query와는 아래와 같이 사용할 수 있습니다.
import { ErrorBoundary } from '@suspensive/react'
import { QueryErrorResetBoundary } from '@tanstack/react-query'
const Example = () => (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallback={(props) => (
<>
<button onClick={props.reset}>Try again</button>
{props.error.message}
</>
)}
>
<Page />
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
)props.onError
<ErrorBoundary/>가 error를 잡을 때 호출되는 callback입니다.
import { ErrorBoundary } from '@suspensive/react'
const logError = (error: Error, info: ErrorInfo) => {
// ...
}
const Example = (
<ErrorBoundary fallback={ErrorBoundaryFallback} onError={logError}>
<ErrorAfter2s />
</ErrorBoundary>
)props.shouldCatch — Suspensive 고유 기능
react-error-boundary나 @sentry/react에는 없는 기능입니다. shouldCatch는 @suspensive/react만의 고유 기능으로, 계층화된 에러 처리를 가능하게 합니다 — 부모와 자식 ErrorBoundary가 서로 다른 에러 타입을 처리할 수 있습니다. 전체 비교를 확인하세요.
shouldCatch는 조건에 따라 <ErrorBoundary/>가 에러를 잡을지 결정합니다.
Boolean, ErrorConstructor, Callback의 3가지 기준을 받으며 기본값은 true입니다.
ErrorConstructor
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect, createElement } from 'react'
export const Example = () => {
return (
<ErrorBoundary
fallback={({ error }) => (
<>Parent ErrorBoundary fallback: {error.message}</>
)}
>
<ErrorBoundary
shouldCatch={CustomError}
fallback={({ error }) => (
<>Child ErrorBoundary fallback: {error.message}</>
)}
>
<CustomErrorAfter2s />
</ErrorBoundary>
</ErrorBoundary>
)
}배열을 통해 여러 조건을 적용할 수도 있습니다.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect, createElement } from 'react'
const Example = () => {
return (
<ErrorBoundary
fallback={({ error }) => (
<>Parent ErrorBoundary fallback: {error.message}</>
)}
>
<ErrorBoundary
shouldCatch={[
false,
CustomError,
(error) => error instanceof CustomError,
]}
fallback={({ error }) => (
<>Child ErrorBoundary fallback: {error.message}</>
)}
>
<CustomErrorAfter2s />
</ErrorBoundary>
</ErrorBoundary>
)
}ErrorBoundary.with
ErrorBoundary.with는 <ErrorBoundary/>의 props를 설정할 수 있는 HOC입니다.
ErrorBoundary.with를 사용하면 컴포넌트를 쉽게 래핑할 수 있습니다.
import { ErrorBoundary, useErrorBoundary } from '@suspensive/react'
const Example = ErrorBoundary.with({ fallback: ErrorBoundaryFallback }, () => {
const errorBoundary = useErrorBoundary()
return <>...</>
})useErrorBoundary
useErrorBoundary().setError
<ErrorBoundary/>의 children에서 useErrorBoundary().setError을 사용해 throw 없이도 <ErrorBoundary/>에서 Error를 알도록 할 수 있습니다.
import { ErrorBoundary, useErrorBoundary } from '@suspensive/react'
import { useEffect } from 'react'
const Example = () => (
<ErrorBoundary fallback={ErrorBoundaryFallback}>
<SetErrorAfterFetch />
</ErrorBoundary>
)
const SetErrorAfterFetch = () => {
const errorBoundary = useErrorBoundary()
useEffect(() => {
fetchSomething().then(
(response) => {},
(error) => errorBoundary.setError(error) // instead of throw inside
)
}, [])
return <>No error</>
}useErrorBoundaryFallbackProps
<ErrorBoundary/>의 fallback 내에서 error 객체와 reset 메소드에 prop drilling 없이 접근할 수 있게 해주는 훅입니다.
Next.js의 React Server Component 환경에서는 서버 컴포넌트에서 클라이언트 컴포넌트로 callback 함수를 props로 전달할 수 없습니다. 이로 인해 <ErrorBoundary/>의 fallback에 함수형 컴포넌트를 전달하여 error와 reset을 받는 것이 불가능합니다. useErrorBoundaryFallbackProps를 사용하면 이러한 제약 없이 fallback 내부에서 error와 reset에 접근할 수 있습니다.
또한 fallback 컴포넌트가 깊게 중첩되는 경우에도, error와 reset을 여러 단계에 걸쳐 전달해야 하는 prop drilling 문제를 해결합니다.
import { ErrorBoundary, useErrorBoundaryFallbackProps } from '@suspensive/react'
const ErrorBoundaryFallback = () => {
const { reset, error } = useErrorBoundaryFallbackProps()
return (
<>
<button onClick={reset}>Try again</button>
{error.message}
</>
)
}
// RSC에서는 fallback에 callback을 전달하지 않고 JSX를 직접 사용해야 합니다
const Example = () => (
<ErrorBoundary fallback={<ErrorBoundaryFallback />}>
<ErrorAfter2s />
</ErrorBoundary>
)useErrorBoundaryFallbackProps는 반드시 <ErrorBoundary/>의 fallback 내부에서 호출해야 합니다. <ErrorBoundary/>의 children 또는 <ErrorBoundary/> 외부에서 호출하면 에러가 발생합니다.