Обработка ошибок

Конвенция файла error.js позволяет элегантно обрабатывать непредвиденные ошибки времени выполнения во вложенных маршрутах.

  • Автоматически оборачивает сегмент маршрута и его вложенные дочерние элементы в React Error Boundary.
  • Создает интерфейс для ошибок, адаптированный к конкретным сегментам, используя иерархию файловой системы для точной настройки.
  • Изолирует ошибки в затронутых сегментах, сохраняя функциональность остальной части приложения.
  • Добавляет возможность попытаться восстановиться после ошибки без полной перезагрузки страницы.

Создайте интерфейс для ошибок, добавив файл error.js внутри сегмента маршрута и экспортировав React-компонент:

error.js special file
'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>Что-то пошло не так!</h2>
      <button
        onClick={
          // Попытка восстановления путем повторного рендеринга сегмента
          () => reset()
        }
      >
        Попробовать снова
      </button>
    </div>
  )
}
'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

How error.js works
  • error.js автоматически создает React Error Boundary, который оборачивает вложенный дочерний сегмент или компонент page.js.
  • React-компонент, экспортированный из файла error.js, используется как резервный компонент.
  • Если ошибка возникает внутри границы ошибки, она изолируется, и отображается резервный компонент.
  • Когда активен резервный компонент ошибки, макеты выше границы ошибки сохраняют свое состояние и остаются интерактивными, а компонент ошибки может предоставить функциональность для восстановления после ошибки.

Восстановление после ошибок

Причина ошибки иногда может быть временной. В таких случаях простая повторная попытка может решить проблему.

Компонент ошибки может использовать функцию reset(), чтобы предложить пользователю попытаться восстановиться после ошибки. При выполнении функция попытается повторно отобразить содержимое границы ошибки. Если попытка успешна, резервный компонент ошибки заменяется результатом повторного рендеринга.

'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Что-то пошло не так!</h2>
      <button onClick={() => reset()}>Попробовать снова</button>
    </div>
  )
}
'use client'

export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Что-то пошло не так!</h2>
      <button onClick={() => reset()}>Попробовать снова</button>
    </div>
  )
}

Вложенные маршруты

React-компоненты, созданные через специальные файлы, отображаются в определенной вложенной иерархии.

Например, вложенный маршрут с двумя сегментами, каждый из которых включает файлы layout.js и error.js, отображается в следующей упрощенной иерархии компонентов:

Nested Error Component Hierarchy

Вложенная иерархия компонентов влияет на поведение файлов error.js во вложенном маршруте:

  • Ошибки всплывают до ближайшей родительской границы ошибок. Это означает, что файл error.js будет обрабатывать ошибки для всех своих вложенных дочерних сегментов. Более или менее детализированный интерфейс ошибок можно достичь, размещая файлы error.js на разных уровнях вложенных папок маршрута.
  • Граница ошибок error.js не будет обрабатывать ошибки, возникающие в компоненте layout.js того же сегмента, потому что граница ошибок вложена внутрь этого компонента макета.

Обработка ошибок в макетах

Границы error.js не перехватывают ошибки, возникающие в компонентах layout.js или template.js того же сегмента. Эта преднамеренная иерархия сохраняет важный интерфейс, общий для родственных маршрутов (например, навигацию), видимым и функциональным при возникновении ошибки.

Для обработки ошибок внутри конкретного макета или шаблона разместите файл error.js в родительском сегменте макета.

Для обработки ошибок в корневом макете или шаблоне используйте вариант error.js под названием global-error.js.

Обработка ошибок в корневых макетах

Корневая граница app/error.js не перехватывает ошибки, возникающие в корневых компонентах app/layout.js или app/template.js.

Для обработки ошибок именно в этих корневых компонентах используйте вариант error.js под названием app/global-error.js, расположенный в корневой директории app.

В отличие от корневого error.js, граница ошибок global-error.js оборачивает все приложение, и ее резервный компонент заменяет корневой макет при активации. Поэтому важно отметить, что global-error.js обязан определять свои собственные теги <html> и <body>.

global-error.js представляет собой наименее детализированный интерфейс ошибок и может считаться "универсальной" обработкой ошибок для всего приложения. Он вряд ли будет часто срабатывать, так как корневые компоненты обычно менее динамичны, и большинство ошибок будут перехвачены другими границами error.js.

Даже если определен global-error.js, все равно рекомендуется определить корневой error.js, чей резервный компонент будет отображаться внутри корневого макета, включая глобально общий интерфейс и брендинг.

'use client'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Что-то пошло не так!</h2>
        <button onClick={() => reset()}>Попробовать снова</button>
      </body>
    </html>
  )
}
'use client'

export default function GlobalError({ error, reset }) {
  return (
    <html>
      <body>
        <h2>Что-то пошло не так!</h2>
        <button onClick={() => reset()}>Попробовать снова</button>
      </body>
    </html>
  )
}

Обработка серверных ошибок

Если ошибка возникает внутри серверного компонента, Next.js передаст объект Error (в production без чувствительной информации об ошибке) в ближайший файл error.js через проп error.

Защита конфиденциальной информации об ошибках

В production объект Error, переданный клиенту, включает только общее свойство message и свойство digest.

Это мера предосторожности, чтобы избежать утечки потенциально конфиденциальных деталей ошибки клиенту.

Свойство message содержит общее сообщение об ошибке, а свойство digest содержит автоматически сгенерированный хэш ошибки, который можно использовать для сопоставления с соответствующей ошибкой в серверных логах.

Во время разработки объект Error, переданный клиенту, будет сериализован и включать message исходной ошибки для упрощения отладки.