React

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

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

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

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

function ErrorComponent() {
  return <h1>Division by 0 Error</h1>
}

Это простой компонент, содержащий тег заголовка с сообщением об ошибке. Как только пользователь попытается разделить число на 0, должен отображаться этот компонент.

Выбрасывание ошибки из компонента React

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

function getDivision() {
  try {
    if (denominator === "0") {
      throw new Error("Division By 0");
    }
    setExecutionOutput(numerator / denominator);
  } catch {
    // Код обработки ошибок
  }
}

Отслеживание ситуации ошибки в случае появления ошибки

Для отслеживания появляющихся ошибок можно использовать переменную состояния. В следующем коде мы создали переменную состояния hasError. Как только код доходит до блока catch, мы можем задать этой переменной состояния значение true:

function getDivision() {
  try {
    if (denominator === "0") {
      throw new Error("Division By 0");
    }
    setExecutionOutput(numerator / denominator);
  } catch {
    setHasError(true);
  }
}

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

Когда вызывается сеттер setHasError и ему присваивается значение true, происходит попытка повторного вывода компонента на экран. При этом мы можем проверить, является ли значение переменной true или false. Если переменная имеет значение true, отображается ErrorComponent. Вот реализация этого шаблона кода:

<div>

  {hasError && <ErrorComponent></ErrorComponent>}

  {!hasError && (
    <section className="App">
      <div>
        <label>First Value:{" "}</label>
        <input id="firstValue" type="text" value={numerator} onChange={updateValue} />
      </div>
      <div>
        <label>Second Value:{" "}</label>
        <input id="secondValue" type="text" value={denominator} onChange={updateValue} />
      </div>
      <div>Output: {executionOutput}</div>
      <input type="button" onClick={getDivision} value="Divide Values" />
    </section>
  )}
</div>

Здесь мы видим, что если hasError имеет значение true, то на экран выводится ErrorComponent. В противном случае отображается обычный HTML-код, принимающий данные пользователя и выдающий результат деления.

Собираем всё вместе

Теперь попробуем объединить все эти отдельные блоки в одно целое. Блок для построения кода состоит из:

  1. Переменной состояния для числителя, знаменателя и executionOutput.
  2. Переменной состояния для отслеживания условия ошибки hasError.
  3. Как только появляется условие ошибки, hasError помечается как true.
  4. Если hasError имеет значение true, то отображается ErrorComponent.
  5. Если hasError имеет значение false, то отображается обычный компонент, принимающий данные пользователя.

Далее приводим весь код:

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  var [numerator, setNumerator] = useState("");
  var [denominator, setDenominator] = useState("");
  var [executionOutput, setExecutionOutput] = useState("");
  var [hasError, setHasError] = useState(false);

  function getDivision() {
    try {
      if (denominator === "0") {
        throw new Error("Division By 0");
      }
      setExecutionOutput(numerator / denominator);
    } catch {
      setHasError(true);
    }
  }

  function updateValue(event) {
    if (event.target.id === "numerator") {
      setNumerator(event.target.value);
    } else {
      setDenominator(event.target.value);
    }
  }

  return (
    <div>
      {!hasError && (
        <section className="App">
          <div>
            <label>First Value:{" "}</label>
            <input id="firstValue" type="text" value={numerator} onChange={updateValue} />
          </div>
          <div>
            <label>Second Value:{" "}</label>
            <input id="secondValue" type="text" value={denominator} onChange={updateValue} />
          </div>
          <div>Output: {executionOutput}</div>
          <input type="button" onClick={getDivision} value="Divide Values" />
        </section>
      )}

      {hasError && <ErrorComponent></ErrorComponent>}
    </div>
  );
}

function ErrorComponent() {
  return <h1>Division by 0 Error</h1>
}

Поэкспериментируйте сами с кодом в этом виртуальном редакторе и попробуйте какой-нибудь сценарий в режиме реального времени:

Заключение:

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

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Mayank Gupta: Error Handling in React Hooks