[Next.js] Error Handling & Error Boundary

 

에러 핸들링은 단순히 에러 메시지를 출력하는 것을 넘어, 에러가 발생했을 때 이를 어떻게 처리할 지에 대한 구체적인 전략을 포함한다.

특히, React에서 제공하는 에러 바운더리는 컴포넌트 트리 내에서 발생한 에러를 감지하고 이를 효과적으로 처리할 수 있는 방법을 제공한다.

 

이번 포스팅에서는 Next.js에서 에러 핸들링을 구현하는 방법과 에러 바운더리를 활용해 에러 처리를 효율적으로 관리하는 방법을 알아보고자 한다.

 

 

01. Error Handling

에러는 크게 두 가지로 나뉜다.

  • 예상 가능한 에러 (Expected Errors) : 정산적인 동작 중에 발생할 수 있는 에러
  • 예상하지 못한 예외 (Uncaught Exceptions) : 예기치 않은 에러로, 일반적으로 어플리케이션의 버그로 간주

 

# 1. 예상 가능한 에러 처리

예상 가능한 에러는 사용자의 잘못된 입력이나 서버 요청 실패 등 예상 가능한 시나리오에서 발생한다.

이 에러는 명시적으로 처리되어야 하며 클라이언트로 반환된다.

 

◼︎ Server Actions에서 예상 가능한 에러 처리

Server Actions는 서버에서 동작하는 로직을 처리하는 영역이다.

여기서 예상 가능한 에러는 return 값을 사용하여 클라이언트로 전달된다.

예외를 throw하는 대신, 에러 메시지를 반환하여 클라이언트가 이를 처리하도록 만든다.

// app/actions.ts
'use server'

import { redirect } from 'next/navigation'

export async function createUser(prevState: any, formData: FormData) {
  const res = await fetch('https://...')
  const json = await res.json()

  if (!res.ok) {
    return { message: 'Please enter a valid email' }
  }

  redirect('/dashboard')
}

위 예시의 동작 과정을 보면 외부 api 통신을 성공하여 서버에서 받은 응답 상태 코드를 확인한다.

해당 상태 코드에 문제가 있으면 에러 메시지를 반환하고 성공하면 다음 동작(리다이렉트 등)을 실행한다.

 

 

◼︎ useFormState를 이용한 에러 상태 관리

useFormState 훅을 사용하여 Server Actions의 결과 상태를 클라이언트에서 관리할 수 있으며 에러 메시지를 렌더링할 수 있다.

이를 통해 사용자 입력 등에 따른 에러 메시지를 화면에 표시할 수 있다.

// app/ui/signup.tsx
'use client'

import { useFormState } from 'react-dom'
import { createUser } from '@/app/actions'

const initialState = {
  message: '',
}

export function Signup() {
  const [state, formAction] = useFormState(createUser, initialState)

  return (
    <form action={formAction}>
      <label htmlFor="email">Email</label>
      <input type="text" id="email" name="email" required />
      <p aria-live="polite">{state?.message}</p>
      <button>Sign up</button>
    </form>
  )
}

 

 

◼︎ Server Components에서 예상 가능한 에러 처리

Server Components에서는 에러를 조건부 렌더링으로 처리하거나 리다이렉션한다.

이는 간단한 에러 처리에 유용하다.

// app/page.tsx
export default async function Page() {
  const res = await fetch(`https://...`)
  const data = await res.json()

  if (!res.ok) {
    return 'There was an error.'
  }

  return '...'
}

 

 

 

#2. 예상하지 못한 예외 처리

예상하지 못한 에러는 어플리케이션의 정상적인 흐름에서 발생해서는 안되는 버그나 문제를 나타내는 에러이다.

이러한 에러는 throw하여 처리해야 하며, 이후 에러 바운더리가 이를 감지하고 처리할 수 있도록 해야한다.

 

일반적으로 루트 레이아웃 하위에서 발생한 예상하지 못한 에러는 error.tsx 파일을 사용하여 처리한다.

하지만 보다 세부적인 에러 처리가 필요한 경우 app/dashboard/error.tsx와 같은 중첩된 error.tsx 파일을 사용하여 처리할 수 있다.

또한 루트 레이아웃에서 발생한 에러는 global-error.tsx 파일을 사용해 처리할 수 있다.

 

 

 

02. Error Boundary

#1. Error Boundary란?

에러 바운더리는 컴포넌트 트리 내에서 발생한 에러를 감지하고 어플리케이션이 전체적으로 다운되는 것을 방지한다. 이를 통해 에러가 발생한 부분만 대체 UI를 보여주고, 나머지 어플리케이션은 정상적으로 작동하도록 만들 수 있다.

 

Next.js에서는 error.tsx 파일을 통해 구현된다.

에러 바운더리는 반드시 클라이언트 컴포넌트로 작성되어야 한다.

다음과 같이 error.tsx 파일을 생성하여 에러 바운더리를 구현할 수 있다.

// app/dashboard/error.tsx
'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>
  )
}

 

 

#2. Nested Routes에서 에러 처리

출처 : https://nextjs.org/docs/app/building-your-application/routing/error-handling

에러는 가장 가까운 부모 에러 바운더리로 전파된다. 이를 통해 계층적이고 세분화된 에러 처리가 가능하다.

 

💡 에러 처리 계층

  1. Route Segment 별 에러 처리: app/dashboard/error.tsx 등 특정 경로의 에러만 처리
  2. 루트 레이아웃 에러 처리: app/error.tsx 또는 app/global-error.tsx에서 전역 에러 처리

 

 

#3. Global Error Handling

루트 레이아웃의 app/global-error.tsx 파일을 통해 애플리케이션 전역의 에러를 처리할 수 있다.

Global Error Boundary는 반드시 <html><body> 태그를 포함해야 한다. 이는 루트 레이아웃이나 템플릿을 대체하기 때문이다.

// 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>
  )
}

 

 

 


References

https://nextjs.org/docs/app/building-your-application/routing/error-handling

 

Routing: Error Handling | Next.js

Learn how to display expected errors and handle uncaught exceptions.

nextjs.org

 

반응형