Поиск по сайту:

Как использовать границы ошибок в React


Введение

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

В этой статье вы узнаете о границах ошибок с помощью фрагментов кода и интерактивных демонстраций.

Предпосылки

Чтобы следовать этой статье, вам понадобятся:

  • Некоторое знакомство с React. Вы можете прочитать нашу серию статей «Как программировать в React.js».

Это руководство было проверено с помощью Node v16.4.2, npm v7.19.1 и react v17.0.2.

Обнаружение ошибок без границ ошибок

Мы неизбежно столкнемся с неожиданными ошибками в наших приложениях во время разработки. Возможно, вы пытаетесь получить доступ к глубоко вложенному свойству объекта, который не существует, или иногда он не находится под вашим контролем (например, неудачный HTTP-запрос к стороннему API).

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

import React from 'react';

class BuggyCounter extends React.Component {
  state = {
    counter: 0,
  };

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1,
    });
  };

  render() {
    if (this.state.counter === 5) {
      // Simulate an error!
      throw new Error('Simulated error.');
    }
    return (
      <div>
        <h1>{this.state.counter}</h1>
        <button onClick={this.handleClick}>+</button>
      </div>
    );
  }
}

export default BuggyCounter;

Посетите живой пример кода @wle8300 на CodePen.

Нажмите кнопку + (приращение) и посмотрите, как она выходит из строя на 5.

Output
Uncaught Error: Simulated error.

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

Границы ошибок позволяют изящно обрабатывать эти ошибки!

Обнаружение ошибок с границами ошибок

Что такое границы ошибки? Вопреки тому, что вы можете подумать, это не новый компонент или библиотека JavaScript. Это больше похоже на стратегию обработки ошибок в компонентах React.

В частности, это использование двух методов, доступных в компонентах React:

import React from 'react';

class MyErrorBoundaryExample extends React.Component {
  state = {
    error: null,
  };

  static getDerivedStateFromError(error) {
    // Update state so next render shows fallback UI.
    return { error: error };
  }

  componentDidCatch(error, info) {
    // Log the error to an error reporting service
    logErrorToExampleService(error, info);
  }

  render() {
    if (this.state.error) {
      // You can render any custom fallback UI
      return <p>Something broke</p>;
    }
    return this.props.children;
  }
}

export default MyErrorBoundaryExample;

  • static getDerivedStateFromError — это метод жизненного цикла, который позволяет границе ошибки обновить состояние и тем самым запустить последний render(). В приведенном выше фрагменте кода состояние используется для отображения сообщения об ошибке вместо неисправного компонента (например, this.props.children).
  • componentDidCatch – это метод жизненного цикла, предназначенный для запуска побочных эффектов (например, регистрации ошибки в таких инструментах, как Crashlytics). Вы можете получить доступ к info.componentStack, чтобы получить удобную для разработчиков трассировку стека, которая будет полезна для сортировки ошибки.

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

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

Давайте немного изменим , а затем обернем его вокруг , чтобы он перехватил ошибку!

import React from 'react';

class MyErrorBoundary extends React.Component {
  state = {
    errorMessage: '',
  };

  static getDerivedStateFromError(error) {
    return { errorMessage: error.toString() };
  }

  componentDidCatch(error, info) {
    this.logErrorToServices(error.toString(), info.componentStack);
  }

  // A fake logging service.
  logErrorToServices = console.log;

  render() {
    if (this.state.errorMessage) {
      return <p>{this.state.errorMessage}</p>;
    }
    return this.props.children;
  }
}

export default MyErrorBoundary;

И App.js:

import React from 'react';
import BuggyCounter from './BuggyCounter';
import MyErrorBoudnary from './MyErrorBoundary';

class App extends React.Component {
  refreshPage = () => {
    history.go(0);
  };

  render() {
    return (
      <div>
        <MyErrorBoundary>
          <BuggyCounter />
        </MyErrorBoundary>
        <hr />
        <button onClick={this.refreshPage}>Refresh Page</button>
      </div>
    );
  }
}

export default App;

BuggyCounter.js остается прежним.

Посетите живой пример кода @wle8300 на CodePen.

Попробуйте снова нажать кнопку + (приращение). Как только он достигнет 5, он изящно рухнет. Кроме того, вы можете открыть консоль для просмотра трассировки стека!

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

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

Сравнение границ ошибок и Try...Catch

Границы ошибок на самом деле не конкурируют напрямую с операторами try...catch. Границы ошибок предназначены только для перехвата ошибок, которые происходят из 3 мест в компоненте React:

  • Во время фазы рендеринга
  • В методе жизненного цикла
  • В конструкторе

По сути… React-части компонента.

В качестве контрапункта, это места, где границы ошибок не смогут поймать ошибку:

  • Обработчики событий (например, onClick, onChange и т. д.)
  • setTimeout или requestAnimationFramecallbacks
  • Визуализация на стороне сервера (SSR)
  • И ошибки, вызванные самой границей ошибки (а не ее потомками)

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

Заключение

В этой статье вы узнали о границах ошибок.

Примечание. Границы ошибок доступны только в компонентах React на основе классов. На момент написания этой статьи в настоящее время не существует способа реализовать это с помощью React Hooks.

Теперь, когда границы ошибок доступны, начиная с версии React 16, обычно рекомендуется использовать хотя бы одну границу ошибок в корне вашего приложения (например, в файле App.js). Это не позволит пользователям увидеть пустую HTML-страницу и, возможно, вместо этого увидит приятный резервный пользовательский интерфейс.

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

Ознакомьтесь с официальной документацией React для получения дополнительной информации!