ReactNextCentral

오류 처리

Published on
라우트 세그먼트와 그 중첩된 자식들을 리액트 오류 경계로 자동으로 감싸서 런타임 오류를 처리합니다.
Table of Contents

error.js 파일을 통한 오류 처리

error.js 파일 규칙은 중첩된 라우트에서 예상치 못한 런타임 오류를 우아하게 처리할 수 있게 해줍니다.

  • 라우트 세그먼트와 그 중첩된 자식들을 리액트 오류 경계로 자동으로 감쌉니다.
  • 파일 시스템 계층 구조를 사용하여 세분화를 조정하며 특정 세그먼트에 맞게 오류 UI를 생성합니다.
  • 오류를 영향을 받은 세그먼트로 격리하면서 애플리케이션의 나머지 부분을 기능적으로 유지합니다.
  • 전체 페이지를 다시 로드하지 않고 오류에서 복구하려는 기능을 추가합니다.

라우트 세그먼트 내에 error.js 파일을 추가하고 리액트 컴포넌트를 내보냄으로써 오류 UI를 생성합니다.

"error.js 특수 파일"

app/dashboard/error.tsx
'use client' // 오류 컴포넌트는 클라이언트 컴포넌트이어야 합니다.

import { useEffect } from 'react'

export default function Error({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  useEffect(() => {
    // 오류 보고 서비스에 오류를 로그합니다.
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>문제가 발생했습니다!</h2>
      <button
        onClick={
          // 세그먼트를 다시 렌더링하려고 시도하여 복구를 시도합니다.
          () => reset()
        }
      >
        다시 시도
      </button>
    </div>
  )
}
JavaScript
app/dashboard/error.js
'use client' // 오류 컴포넌트는 클라이언트 컴포넌트이어야 합니다.

import { useEffect } from 'react'

export default function Error({ error, reset }) {
  useEffect(() => {
    // 오류 보고 서비스에 오류를 로그합니다.
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>문제가 발생했습니다!</h2>
      <button
        onClick={
          // 세그먼트를 다시 렌더링하려고 시도하여 복구를 시도합니다.
          () => reset()
        }
      >
        다시 시도
      </button>
    </div>
  )
}

error.js의 동작 방식

"error.js 동작 방식"

  • error.js는 중첩된 자식 세그먼트나 page.js 컴포넌트를 감싸는 리액트 오류 경계를 자동으로 생성합니다.
  • error.js 파일에서 내보낸 리액트 컴포넌트는 대체 컴포넌트로 사용됩니다.
  • 오류 경계 내에서 오류가 발생하면, 해당 오류는 포함되며, 대체 컴포넌트가 렌더링됩니다.
  • 대체 오류 컴포넌트가 활성화되어 있을 때, 오류 경계 의 레이아웃은 상태를 유지하며 상호 작용이 가능하고, 오류 컴포넌트는 오류에서 복구하는 기능을 표시할 수 있습니다.

오류에서 복구하기

오류의 원인은 때때로 일시적일 수 있습니다. 이러한 경우, 단순히 다시 시도하는 것만으로 문제를 해결할 수 있습니다.

오류 컴포넌트는 reset() 함수를 사용하여 사용자에게 오류에서 복구하도록 시도할 수 있습니다. 실행될 때, 이 함수는 오류 경계의 내용을 다시 렌더링하려고 시도합니다. 성공하면, 대체 오류 컴포넌트는 다시 렌더링의 결과로 교체됩니다.

app/dashboard/error.tsx
'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  return (
    <div>
      <h2>문제가 발생했습니다!</h2>
      <button onClick={() => reset()}>다시 시도</button>
    </div>
  )
}
JavaScript
app/dashboard/error.js
'use client'

export default function Error({ error, reset }) {
  return (
    <div>
      <h2>문제가 발생했습니다!</h2>
      <button onClick={() => reset()}>다시 시도</button>
    </div>
  )
}

중첩 라우트

특별한 파일을 통해 생성된 리액트 컴포넌트들은 특정 중첩 계층에서 렌더링됩니다.

예를 들어, 두 개의 세그먼트를 포함하는 중첩 라우트가 layout.jserror.js 파일을 포함하면 다음 간단한 컴포넌트 계층에서 렌더링됩니다.

"중첩 오류 컴포넌트 계층"

중첩된 컴포넌트 계층은 중첩된 라우트의 error.js 파일의 동작에 영향을 줍니다.

  • 오류는 가장 가까운 부모 오류 경계로 전달됩니다. 이는 error.js 파일이 모든 중첩된 자식 세그먼트의 오류를 처리한다는 것을 의미합니다. 라우트의 중첩 폴더의 다양한 레벨에 error.js 파일을 배치함으로써 더욱 세밀한 오류 UI를 구현할 수 있습니다.
  • error.js 경계는 동일한 세그먼트의 layout.js 컴포넌트에서 발생하는 오류를 처리하지 않습니다. 왜냐하면 오류 경계는 레이아웃 컴포넌트 안쪽에 중첩되어 있기 때문입니다.

레이아웃에서의 오류 처리

error.js 경계는 동일한 세그먼트layout.js 또는 template.js 컴포넌트에서 발생하는 오류를 잡아내지 않습니다. 이 의도적 계층 구조는 오류가 발생했을 때 형제 라우트간에 공유되는 중요한 UI(예: 내비게이션)가 보이고 기능하도록 유지합니다.

특정 레이아웃 또는 템플릿 내의 오류를 처리하려면, 레이아웃의 부모 세그먼트에 error.js 파일을 배치합니다. 루트 레이아웃 또는 템플릿 내의 오류를 처리하려면, error.js의 변형 버전인 global-error.js를 사용합니다.

루트 레이아웃에서의 오류 처리: app/global-error.js 사용

루트 app/error.js 경계는 루트 app/layout.js 또는 app/template.js 컴포넌트에서 발생하는 오류를 잡아내지 않습니다.

이러한 루트 컴포넌트에서의 오류를 특별히 처리하려면, 루트 app 디렉토리에 위치한 error.js의 변형 버전인 app/global-error.js를 사용합니다.

루트 error.js와 달리, global-error.js 오류 경계는 전체 애플리케이션을 감싸고, 그 대체 컴포넌트는 활성 상태일 때 루트 레이아웃을 대체합니다. 이 때문에 global-error.js는 자체 <html><body> 태그를 정의해야 한다는 것을 유의해야 합니다.

global-error.js는 가장 세밀하지 않은 오류 UI이며, 전체 애플리케이션에 대한 "모든 것을 잡는" 오류 처리로 간주될 수 있습니다. 루트 컴포넌트는 일반적으로 동적이지 않기 때문에 자주 트리거되지 않으며, 다른 error.js 경계가 대부분의 오류를 잡아냅니다.

global-error.js가 정의되어 있더라도, 전역적으로 공유되는 UI와 브랜딩을 포함하는 루트 레이아웃 내부에서 렌더링될 대체 컴포넌트를 정의하는 루트 error.js를 정의하는 것이 여전히 권장됩니다.

app/global-error.tsx
'use client'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>문제가 발생했습니다!</h2>
        <button onClick={() => reset()}>다시 시도</button>
      </body>
    </html>
  )
}
JavaScript
app/global-error.js
'use client'

export default function GlobalError({ error, reset }) {
  return (
    <html>
      <body>
        <h2>문제가 발생했습니다!</h2>
        <button onClick={() => reset()}>다시 시도</button>
      </body>
    </html>
  )
}

서버 오류 처리

서버 컴포넌트 내에서 오류가 발생하면 Next.js는 error prop로 가장 가까운 error.js 파일에 Error 객체(프로덕션에서는 민감한 오류 정보가 제거된)를 전달합니다.

민감한 오류 정보 보안

프로덕션 환경에서는 클라이언트에 전달된 Error 객체는 일반적인 messagedigest 속성만을 포함합니다. 이는 오류에 포함된 잠재적으로 민감한 정보를 클라이언트에 누출하는 것을 방지하기 위한 보안 조치입니다.

message 속성에는 오류에 대한 일반적인 메시지가 포함되어 있으며, digest 속성에는 서버측 로그의 해당 오류와 일치시키는 데 사용할 수 있는 자동 생성된 오류의 해시가 포함됩니다. 개발 중에는 클라이언트에 전달된 Error 객체가 직렬화되어 원래의 오류의 message를 포함하여 디버깅이 더 쉽게 됩니다.