Обробка помилок у React 16

Оскільки випуск React 16 ближче, ми хотіли б оголосити кілька змін у тому, як React обробляє помилки JavaScript усередині компонентів. Ці зміни включені в бета-версії React 16 і стануть частиною React 16.

До речі, ми просто випустили першу бета-версію React 16 для вас, щоб спробувати!

Поведінка у React 15 та попередніх версіях.

У минулому, помилки JavaScript усередині компонентів, які використовуються для корумпованості внутрішнього стану React, і викликають вираження криптичних помилок на наступних рендерингах. Ці помилки завжди були викликані більш ранньою помилкою в коді програми, але React не надав способу чітко їх обробляти в компонентах і не міг відновити їх.

Представляємо граничні помилки.

Помилка JavaScript у частині інтерфейсу не повинна зламати весь додаток. Щоб вирішити цю проблему для користувачів React, React 16 представляє нову концепцію “межі помилки”.

Межі помилок – це реагувати компоненти, які виводять JavaScript-помилки в будь-якому місці дерева їхніх дочірніх компонентів, реєструють ці помилки та показують залежний інтерфейс замість дерева компонентів, що зазнали аварії. Межі помилок виводяться помилки під час рендеринга, в методах життєвого циклу та в конструкторів цілого дерева нижче них.

Компонент класу стає границею помилки, якщо він визначає новий метод життєвого циклу, який називається componentDidCatch(error, info):

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

  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  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>

componentDidCatch() Метод працює як JavaScript catch {} блок, але для компонентів. Тільки компоненти класу можуть бути межами помилки. На практиці більшу частину часу ви хочете одночасно оголосити граничний компонент помилки і використовувати його у своїй заявці.

Зверніть увагу, що межі помилок виявляють лише помилки компонентів під ними у дереві . Межа помилки не може зловити помилку всередині себе. Якщо гранична помилка не намагається відобразити повідомлення про помилку, помилка буде поширюватися на найближчу межу помилки над нею. Це теж схоже на те, як catch {} блок працює в JavaScript.

Live Demo

Перегляньте цей приклад декларування та використання межі помилки з бета-версією React 16.

Де розмістити межі помилок

Деталізація меж помилок залежить від вас. Ви можете обернути компоненти маршруту верхнього рівня, щоб показати користувачеві повідомлення “щось пошкоджено”, подібно до того, як на стороні сервера часто обробляються збої. Ви також можете загорнути окремий віджет у межах помилки, щоб захистити їх від збою іншої частини програми.

Нова поведінка для невиконаних помилок.

Ця зміна має важливе значення. По відношенню до React 16, помилки, які не потрапляли в будь-яку межу помилки, призведуть до відключення всього дерева компонентів React.

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

Ця зміна означає, що коли ви переходите на React 16, ви, ймовірно, розкриєте існуючі збої у вашій програмі, які раніше були непоміченими. Додавання меж помилок дозволяє забезпечити кращу взаємодію з користувачем, коли щось піде не так.

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

Ми також пропонуємо вам використовувати служби звітування про помилки JS (або створювати власні), щоб ви могли дізнатись про невикористані винятки, як це трапляється у виробництві, та виправити їх.

Стеки компонентів

React 16 виводить всі помилки, що відбулися під час відтворення, до консолі в процесі розробки, навіть якщо програма випадково проковтнула їх. Окрім повідомлення про помилку та стеку JavaScript, він також забезпечує сліди стеку компонентів. Тепер ви можете побачити, де саме в дереві компонент виникла помилка:

Компонентні стеки слідують у повідомленні про помилку

Ви також можете побачити імена файлів і рядки в трасі стеку компонентів. Це працює за замовчуванням у проектах Create React App:

Компонентні стеки з номерами рядків у повідомленні про помилку

Якщо ви не використовуєте програму Create React App, ви можете додати цей плагін вручну в свою конфігурацію Babel. Зверніть увагу, що він призначений тільки для розробки та повинен бути відключений у виробництві.

Чому б не користуватися try / catch?

try / catch Чудово, але працює лише для обов’язкового коду:

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

Проте компоненти React є декларативними та вказують, що потрібно зробити:

<Button />

Межі помилок зберігають декларативний характер React і ведуть себе так, як ви очікуєте. Наприклад, навіть якщо в componentDidUpdate гачку виникає помилка, викликана setState десь глибоко в дереві, вона все одно коректно поширюється до найближчої межі помилки.

Іменування змін від React 15

Реагувати 15 включав в себе дуже обмежену підтримку кордонів помилок під іншим ім’ям методу: unstable_handleError. Цей метод більше не працює, і вам потрібно буде змінити його componentDidCatchу вашому коді, починаючи з першого 16 бета-версії.

Для цієї зміни ми надали codemod для автоматичного переміщення вашого коду.

Переклад статті.