Spec-Zone.ru › React 17

Границы обработки ошибок

В прошлом ошибки JavaScript внутри компонентов могли портить внутреннее состояние React и заставлять его выдавать непонятные ошибки при следующих отрисовках. Эти ошибки всегда вызывались более ранними ошибками в коде приложения, но React не предоставлял способ их обработки в компонентах без сбоев и не мог их исправить.

Введение границ обработки ошибок

Ошибка JavaScript в части пользовательского интерфейса не должна ломать всё приложение. Для решения этой проблемы для пользователей React, React 16 вводит новое понятие «границы обработки ошибок».

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

Примечание

Границы обработки ошибок не перехватывают ошибки для:

  • Обработчиков событий (подробнее)
  • Асинхронного кода (например, setTimeout или requestAnimationFrame обратных вызовов)
  • Отрисовки на стороне сервера
  • Ошибок, выброшенных в самой границе обработки ошибок (а не её дочерними элементами)

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

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

Затем вы можете использовать его как обычный компонент:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

Границы обработки ошибок работают как блок JavaScript catch {} для компонентов. Только компоненты класса могут быть границами обработки ошибок. На практике вы, скорее всего, захотите объявить компонент границы обработки ошибок один раз и использовать его во всём приложении.

Обратите внимание, что границы обработки ошибок перехватывают ошибки только в компонентах ниже их в древовидной структуре. Граница обработки ошибок не может перехватить ошибку внутри себя. Если граница обработки ошибок не может отобразить сообщение об ошибке, ошибка распространится до ближайшей границы обработки ошибок выше её. Это также аналогично тому, как работает блок catch {} в JavaScript.

Демо-версия

Посмотрите этот пример объявления и использования границы обработки ошибок с React 16.

Где размещать границы обработки ошибок

Степень детализации границ обработки ошибок зависит от вас. Вы можете обернуть компоненты маршрутов верхнего уровня, чтобы отобразить пользователю сообщение «Что-то пошло не так», точно так же, как фреймворки на стороне сервера часто обрабатывают сбои. Вы также можете обернуть отдельные виджеты в границу обработки ошибок, чтобы защитить их от сбоя остальной части приложения.

Новое поведение для неперехваченных ошибок

Это изменение имеет важное значение. Начиная с React 16, ошибки, которые не были перехвачены какой-либо границей обработки ошибок, приведут к размонтированию всей древовидной структуры компонента React.

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

Это изменение означает, что при переходе на React 16 вы, вероятно, обнаружите существующие сбои в вашем приложении, которые раньше оставались незамеченными. Добавление границ обработки ошибок позволяет предоставить лучший пользовательский опыт, когда что-то идёт не так.

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

Мы также рекомендуем использовать службы отслеживания ошибок JavaScript (или создать свои собственные), чтобы вы могли узнавать о необработанных исключениях в производстве и исправлять их.

Стек-трейсы компонентов

React 16 печатает все ошибки, возникшие во время отрисовки, в консоль в режиме разработки, даже если приложение случайно их проглотит. В дополнение к сообщению об ошибке и стеку JavaScript, он также предоставляет стеки отслеживания компонентов. Теперь вы можете увидеть, где именно в древовидной структуре компонента произошёл сбой:

Error caught by Error Boundary component

Вы также можете увидеть имена файлов и номера строк в стеке отслеживания компонентов. Это работает по умолчанию в проектах Create React App:

Error caught by Error Boundary component with line numbers

Если вы не используете Create React App, вы можете вручную добавить этот плагин в свою конфигурацию Babel. Обратите внимание, что он предназначен только для разработки и должен быть отключён в продакшене.

Примечание

Имена компонентов, отображаемые в стеках отслеживания, зависят от свойства Function.name. Если вы поддерживаете более старые браузеры и устройства, которые ещё не поддерживают это в своём родном виде (например, IE 11), подумайте о включении Function.name полифилла в ваше скомпонованное приложение, например, function.name-polyfill. В качестве альтернативы, вы можете явно установить свойство displayName на все ваши компоненты.

А как насчёт try/catch?

try / catch отлично, но это работает только для императивного кода:

try {
  showButton();
} catch (error) {
  // ...
}

Однако компоненты React декларативны и указывают, что должно быть отображено:

<Button />

Границы обработки ошибок сохраняют декларативную природу React и ведут себя так, как вы ожидаете. Например, даже если ошибка произойдёт в методе componentDidUpdate вызванная ошибкой setState где-то глубоко в древовидной структуре, она всё ещё корректно будет распространена до ближайшей границы обработки ошибок.

А как насчёт обработчиков событий?

Границы обработки ошибок не перехватывают ошибки внутри обработчиков событий.

React не нуждается в границах обработки ошибок для восстановления из ошибок в обработчиках событий. В отличие от метода отрисовки и методов жизненного цикла, обработчики событий не происходят во время отрисовки. Таким образом, если они выбросят ошибку, React всё равно знает, что отобразить на экране.

Если вам нужно перехватить ошибку внутри обработчика событий, используйте обычное JavaScript-утверждение try / catch:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    try {
      // Do something that could throw
    } catch (error) {
      this.setState({ error });
    }
  }

  render() {
    if (this.state.error) {
      return <h1>Caught an error.</h1>
    }
    return <button onClick={this.handleClick}>Click Me</button>
  }
}

Обратите внимание, что приведенный выше пример демонстрирует обычное поведение JavaScript и не использует границы обработки ошибок.

Изменения имён с React 15

React 15 включал очень ограниченную поддержку границ обработки ошибок под другим именем метода: unstable_handleError. Этот метод больше не работает, и вам необходимо изменить его на componentDidCatch в вашем коде, начиная с первой бета-версии 16.

Для этого изменения мы предоставили codemod для автоматической миграции вашего кода.

Полезная ли эта страница?

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://17.reactjs.org/docs/error-boundaries.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API