Как обрабатывать ошибки в React

автор


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

Типы ошибок реагирования

Мы можем разделить ошибки приложения React на два типа, а обработку ошибок — на два аспекта.

Два типа ошибок React:

  • Ошибки JavaScript. Это обычные ошибки JavaScript, возникающие в части кода компонента.
  • Ошибки рендеринга: это ошибки, возникающие в механизме рендеринга и возникающие в разметке.

Обратите внимание, что природа пользовательского интерфейса JavaScript затрудняет обработку ошибок. Помимо типичных ошибок во время выполнения, существуют ошибки, возникающие из-за «отрисовки» компонентов экрана. Здесь мы различаем эти два типа ошибок как «ошибки JavaScript» и «ошибки рендеринга».

Ошибки JavaScript возникают в коде и могут быть обработаны с помощью стандартных блоков try/catch, тогда как ошибки рендеринга возникают в шаблонах представлений и обрабатываются границами ошибок React. Мы можем думать о границах ошибок как о блоках try/catch, выраженных в разметке шаблона.

В обоих случаях есть два аспекта обработки ошибок:

  • Отображение информации пользователю
  • Предоставление информации разработчику

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

Реагировать на границы ошибок

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

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

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

Эти два метода componentDidCatch() и getDerivedStateFromError(), который является статическим. В обоих случаях основная цель — обновить состояние компонента, чтобы он мог реагировать на ошибки, поступающие из механизма React.

компонентDidCatch()

componentDidCatch() является нормальным и может обновлять состояние компонента, а также выполнять такие действия, как вызов службы на серверную часть, сообщающую об ошибках. В листинге 1 показано, как мы используем этот метод.

Листинг 1. компонентDidCatch


componentDidCatch(error, errorInfo) {
    errorService.report(errorInfo);
    this.setState({ error: error, errorInfo: errorInfo })
  }

В листинге 1 основная функция гарантирует, что состояние компонента понимает, что произошла ошибка, и передает информацию об этой ошибке. Обратите внимание, что это componentDidCatch() имеет доступ к среде выполнения.

getDerivedStateFromError()

Потому что getDerivedFromError() является статическим, у него нет доступа к состоянию компонента. Его единственная цель — получить объект ошибки, а затем вернуть объект, который будет добавлен в состояние компонента. Например, см. листинг 2.

Листинг 2. getDerivedStateFromError()


static getDerivedStateFromError(error) {
  return { isError: true };
}

Листинг 2 возвращает объект с флагом ошибки, который затем может использоваться компонентом при отрисовке. Мы могли бы справиться с более сложными задачами, создав более сложные объекты ошибок.

Рендеринг на основе ошибки

Теперь давайте посмотрим на отрисовку нашего компонента обработки ошибок, как показано в листинге 3.

Листинг 3. Отрисовка ErrorBoundary


render() {
  if (this.state.error && this.state.errorInfo) {
    return (
      <div>
        <p>Caught an Error: {this.state.error.toString()}</p>
        <div>
          {this.state.errorInfo.componentStack}
        </div>
      </div>
    );
  } else {
    return this.props.children;
  }
}

Из листинга 3 видно, что действие компонента по умолчанию — отрисовка дочерних элементов. То есть это простой сквозной компонент. Если обнаружено состояние ошибки (как в листинге 1 или листинге 2), то отображается альтернативное представление. Хотя поведение по умолчанию заключается в рендеринге интерфейса, состояние ошибки вызывает альтернативный путь, что-то вроде блока catch.

Использование компонента ErrorBoundary

Теперь вы познакомились с основными элементами компонента обработки ошибок в React. Использовать компонент очень просто, как показано в листинге 4.

Листинг 4. Пример компонента ErrorBoundary


<Parent>
  <ErrorBoundary>
    <Child><Child/>
  </ErrorBoundary>
</Parent>

В листинге 4 любые ошибки рендеринга в <Child> вызовет альтернативный рендеринг обработки ошибок <ErrorBoundary> компонент. Вы можете видеть, что компоненты границ ошибок действуют как своего рода декларативный блок try/catch в представлении. Любые дети из <Child> также будет пузыриться до <ErrorBoundary> если только они не будут пойманы какой-либо другой границей ошибки на этом пути — это также аналогично поведению try/catch.

Ошибки JavaScript

Ошибки JavaScript обрабатываются путем заключения кода в блоки try/catch, как в стандартном JavaScript. Это хорошо понятно и отлично работает, но есть несколько комментариев, которые следует сделать в контексте пользовательского интерфейса React.

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

Сетевые ошибки

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

Листинг 5. Использование встроенных кодов ошибок


let response = await fetch(process.env.REACT_APP_API + 
'/api/describe?_id='+this.state.projectId, {
        headers: { "Authorization": this.props.userData.userData.jwt },
        method: 'GET',
      });
      if (response.ok){
        let json = await response.json();
        console.info(json);
        this.setState({ "project": json});
      } else {
        console.error("Problem: " + response);
        throw new Error(“Problem fetching user info”, response);
      }

Цель листинга 5 — использовать стандартные коды состояния HTTP для определения состояния ошибки сетевого запроса. (Иногда возникает соблазн использовать собственное поле «статус».) В этом случае ошибка обнаруживается путем проверки response.okа затем, если есть ошибка, мы создаем новую ошибку с помощью throw. В этом случае мы ожидаем, что обработчик catch справится с ситуацией.

Наконец, что касается ошибок рендеринга и JavaScript, помните, что может быть полезно регистрировать ошибки через API удаленных отчетов об ошибках. Это обрабатывается компонентами на основе классов, которые реализуют componentDidCatch метод.

Обработка ошибок в действии

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

Итак, это дает вам представление о коде и поведении нескольких возможных состояний ошибки:

  • При нажатии на зеленое поле выдается ошибка времени рендеринга, и оно фиксируется границей, отображая сообщение об ошибке.
  • Красный прямоугольник выдаст ошибку рендеринга без границы, и, как вы можете видеть, приложение выйдет из строя и рендеринг прекратится.
  • Синий и фиолетовый поля обрабатывают ошибки одинаково, поскольку граница ошибки не фиксирует ошибку JavaScript.

Эти примеры заслуживают изучения, поскольку они дают вам все рабочие элементы границ ошибок в небольшом пакете.

Возможно, вам также будет полезно ознакомиться с примером границ ошибок в React 16 на CodePen.

Заключение

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

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

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

Дальше читайте это:

  • Почему компании уходят из облака
  • 5 простых способов запустить LLM локально
  • Программирование с помощью ИИ: советы и лучшие практики от разработчиков
  • Знакомьтесь, Zig: современная альтернатива C
  • Что такое генеративный ИИ? Искусственный интеллект, который создает
  • Лучшее программное обеспечение с открытым исходным кодом 2023 года

Related Posts

Оставить комментарий