error.js 파일 컨벤션은 중첩 라우트에서 발생하는 예상치 못한 런타임 에러를 우아하게 처리할 수 있도록 도와줍니다.
- 자동으로 라우트 세그먼트와 자식 세그먼트를 리액트 에러 바운더리로 감싸줍니다.
- 세분성을 조절하기 위해 파일 시스템 계층 구조를 사용하여 특정 세그먼트에 최적화 된 에러 UI를 생성할 수 있습니다.
- 나머지 기능은 그대로 유지한 채로 에러가 발생한 세그먼트만 분리할 수 있습니다.
- 전체 페이지 로딩을 하지 않고 에러를 핸들링 할 수 있는 기능을 추가할 수 있습니다.
error.js 파일을 라우트 세그먼트에 위치하고 리액트 컴포넌트를 export 하면 에러 UI를 생성할 수 있습니다.
공식 문서에서 제공하는 error.js의 기본 예시 코드는 아래와 같습니다.
'use client' // 에러 컴포넌트는 클아이언트 컴포넌트여야 한다.
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// 에러 로그
console.error(error)
}, [error])
return (
<div>
<h2>Something went wrong!</h2>
<button
onClick={
// 세그먼트를 다시 리렌더링 하여 에러를 핸들링함
() => reset()
}
>
Try again
</button>
</div>
)
}
error.js 동작 방식
- error.js 파일은 page.js 컴포넌트나 중첩 된 자식 세그먼트를 감싸는 리액트 에러 바운더리를 자동으로 생성합니다.
- error.js 파일에서 export 되는 리액트 컴포넌트는 리액트 에러 바운더리에 fallback 컴포넌트로 사용 됩니다.
- 에러 바운더리 내에서 에러가 발생하면 에러 객체가 포함 된 fallback 컴포넌트는 렌더링 됩니다.
- fallback 에러 컴포넌트가 활성화 됬을 때 에러 바운더리 컴포넌트의 상위 컴포넌트로 자리 잡은 레이아웃은 스테이트를 유지하고 인터랙션 능력을 유지합니다. 그리고 에러 컴포넌트는 에러를 핸들링 할 수 있는 기능을 UI로 보여줄 수 있습니다.
오류 복구하기
에러의 발생 원인은 때로는 일시적일 수 있습니다.
이런 경우엔 다시 시도해보는게 이슈를 해결할 방법이 될 수 있습니다.
에러 컴포넌트는 reset() 함수를 사용하여 유저가 에러를 핸들링 할 수 있도록 처리합니다.
함수가 실행 되면 에러 바운더리 내의 컨텐츠를 리렌더링 합니다.
만약 성공했다면 fallback 에러 컴포넌트는 성공한 렌더링 결과물과 스왑하게 됩니다.
'use client'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<div>
<h2>Something went wrong!</h2>
// reset 함수를 통해 리렌더링 가능
<button onClick={() => reset()}>Try again</button>
</div>
)
}
중접 라우팅의 경우
특수 파일로 만들어진 리액트 컴포넌트는 특별한 중첩 계층 구조를 가진채 렌더링 됩니다.
예를 들어 layout.js 파일과 error.js 파일을 가지고 있는 중첩 된 두 라우트 세그먼트는 다음의 간단한 컴포넌트 계층 구조를 가지게 됩니다.
중첩 컴포넌트 계층 구조는 중첩 라우트 간 다음의 error.js 파일의 행동을 내포하고 있습니다.
- 에러는 가장 가까운 부모 에러 바운더리로 버블링 됩니다. 따라서 error.js 파일은 중첩 되어 있는 자식 세그먼트의 에러도 핸들링 할 수 있습니다. 에러 UI의 많고 적은 입자감은 중첩 폴더 혹은 라우트에서 error.js 를 어느 위치에 놓는지로 성취할 수 있습니다.
- error.js 경계는 동일 세그먼트에 선언 된 layout.js 에서 발생 되는 에러를 핸들링 하지 못합니다. 왜냐면 에러 바운더리는 레이아웃 컴포넌트 내부에 위치하기 때문입니다.
layout.js 오류 처리
error.js 경계는 동일 세그먼트의 layout.js, template.js 컴포넌트의 에러를 잡아내지 못합니다.
이런 의도 된 계층 구조 원칙은 네비게이션 같은 형제 라우트간 공유 되는 중요 UI를 에러가 발생하더라도 볼 수 있도록 유지합니다.
특정 레이아웃, 템플릿에서 에러를 핸들링하고 싶다면 레이아웃의 부모 세그먼트에 error.js 파일을 생성하면 됩니다.
루트 레이아웃, 템플릿에서 에러를 핸들링하기 위해선 error.js 의 변형인 global-error.js 컴포넌트를 사용하면 됩니다.
Root layout.js 오류 처리
app/error.js 루트 바운더리는 app/layout.js , app/template.js 같은 루트 컴포넌트의 에러를 잡아내지 못합니다.
특별히 루트 컴포넌트에서 에러를 핸들링 하기 위해 error.js의 변형인 app/global-error.js 파일을 app 디렉토리에 위치하여 해결할 수 있습니다.
루트 error.js 컴포넌트와 다르게 global-error.js 에러 바운더리는 어플리케이션 전체를 감싸고 fallback UI가 활성화 되면 루트 레이아웃을 대체하게 됩니다.
이런 이유 때문에 global-error.js 컴포넌트는 자신만의 <html> , <body> 태그를 반드시 포함해야 합니다.
global-error.js 컴포넌트는 최소한의 파편(granular) 에러 UI이고 어플리케이션 전체에서 "catch-all" 에러 핸들링 컴포넌트라고 간주할 수 있습니다.
내부의 다른 error.js 바운더리가 대부분의 에러를 핸들링 하기도 하고, 루트 컴포넌트는 대부분 다이나믹하지 않기 때문에 에러 바운더리가 트리거 될 일은 흔하지 않습니다.
global-error.js 컴포넌트가 정의 되었다고 해도 글로벌하게 공유 되는 UI와 브랜딩을 가지고 있는 루트 레이아웃 내부에서 fallback 컴포넌트가 렌더링 되는 루트 error.js 컴포넌트를 정의하는 것을 추천합니다.(global-error.js 컴포넌트는 fallback UI가 렌더링 되면 전체 레이아웃도 같이 사라지기 때문입니다.)
// app/global-error.tsx
'use client'
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<html>
<body>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</body>
</html>
)
}
'study > Next.js' 카테고리의 다른 글
Next.js 13 - [next-auth][error][CLIENT_FETCH_ERROR] 오류 (2) | 2023.04.25 |
---|---|
Next.js 13 - Warning: Prop `style` did not match. Server 오류 (0) | 2023.04.20 |
Next.js 13 - ReferenceError: window is not defined 오류 (0) | 2023.04.17 |