error.js

Файл error позволяет обрабатывать непредвиденные ошибки во время выполнения и отображать резервный интерфейс.

Специальный файл 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 оборачивает сегмент маршрута и его вложенные дочерние элементы в React Error Boundary. При возникновении ошибки внутри границы компонент error отображается как резервный интерфейс.

Как работает error.js

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

  • React DevTools позволяют переключать границы ошибок для тестирования состояний с ошибками.
  • Если вы хотите, чтобы ошибки передавались в родительскую границу ошибок, можно использовать throw при рендеринге компонента error.

Справочник

Пропсы

error

Экземпляр объекта Error, переданный в клиентский компонент error.js.

Полезно знать: В процессе разработки объект Error, переданный клиенту, будет сериализован и включать message исходной ошибки для упрощения отладки. Однако в продакшене это поведение отличается, чтобы избежать утечки потенциально конфиденциальных данных, содержащихся в ошибке, на клиент.

error.message

  • Ошибки, переданные из клиентских компонентов, показывают оригинальное сообщение Error.
  • Ошибки, переданные из серверных компонентов, показывают общее сообщение с идентификатором. Это сделано для предотвращения утечки конфиденциальных данных. Идентификатор, доступный в errors.digest, можно использовать для сопоставления с соответствующими серверными логами.

error.digest

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

reset

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

Компонент ошибки может использовать функцию 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>
  )
}

Примеры

Глобальная ошибка

Хотя это менее распространено, вы можете обрабатывать ошибки в корневом макете или шаблоне с помощью global-error.js, расположенного в корневой директории приложения, даже при использовании интернационализации. Глобальный интерфейс ошибки должен определять свои собственные теги <html> и <body>. Этот файл заменяет корневой макет или шаблон при активации.

'use client' // Границы ошибок должны быть клиентскими компонентами

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

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

Плавное восстановление после ошибок с пользовательской границей ошибок

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

GracefullyDegradingErrorBoundary — это пример пользовательской границы ошибок, которая захватывает и сохраняет текущий HTML до возникновения ошибки. Если происходит ошибка рендеринга, она повторно отображает захваченный HTML и показывает постоянное уведомление для информирования пользователя.

'use client'

import React, { Component, ErrorInfo, ReactNode } from 'react'

interface ErrorBoundaryProps {
  children: ReactNode
  onError?: (error: Error, errorInfo: ErrorInfo) => void
}

interface ErrorBoundaryState {
  hasError: boolean
}

export class GracefullyDegradingErrorBoundary extends Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  private contentRef: React.RefObject<HTMLDivElement>

  constructor(props: ErrorBoundaryProps) {
    super(props)
    this.state = { hasError: false }
    this.contentRef = React.createRef()
  }

  static getDerivedStateFromError(_: Error): ErrorBoundaryState {
    return { hasError: true }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    if (this.props.onError) {
      this.props.onError(error, errorInfo)
    }
  }

  render() {
    if (this.state.hasError) {
      // Рендеринг текущего HTML-содержимого без гидратации
      return (
        <>
          <div
            ref={this.contentRef}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: this.contentRef.current?.innerHTML || '',
            }}
          />
          <div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
            <p className="font-semibold">
              Произошла ошибка во время рендеринга страницы
            </p>
          </div>
        </>
      )
    }

    return <div ref={this.contentRef}>{this.props.children}</div>
  }
}

export default GracefullyDegradingErrorBoundary
'use client'

import React, { Component, createRef } from 'react'

class GracefullyDegradingErrorBoundary extends Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
    this.contentRef = createRef()
  }

  static getDerivedStateFromError(_) {
    return { hasError: true }
  }

  componentDidCatch(error, errorInfo) {
    if (this.props.onError) {
      this.props.onError(error, errorInfo)
    }
  }

  render() {
    if (this.state.hasError) {
      // Рендеринг текущего HTML-содержимого без гидратации
      return (
        <>
          <div
            ref={this.contentRef}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: this.contentRef.current?.innerHTML || '',
            }}
          />
          <div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
            <p className="font-semibold">
              Произошла ошибка во время рендеринга страницы
            </p>
          </div>
        </>
      )
    }

    return <div ref={this.contentRef}>{this.props.children}</div>
  }
}

export default GracefullyDegradingErrorBoundary

История версий

ВерсияИзменения
v15.2.0Также отображает global-error в разработке.
v13.1.0Введен global-error.
v13.0.0Введен error.