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

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

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

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

Специальный файл 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>Что-то пошло не так!</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

Принцип работы error.js
  • 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, отображается в следующей упрощенной иерархии компонентов:

Иерархия вложенных компонентов ошибок

Вложенная иерархия компонентов влияет на поведение файлов 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>
  )
}

Полезно знать:

  • global-error.js активен только в production. В development вместо него будет показано наше оверлейное сообщение об ошибке.

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

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

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

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

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

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

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