JavaRush /Курсы /Модуль 3: React /Создание HOC для добавления логики к компонентам — обрабо...

Создание HOC для добавления логики к компонентам — обработка ошибок

Модуль 3: React
4 уровень , 1 лекция
Открыта

Как используются HOC для обработки ошибок?

Представьте, что ваше React-приложение — это большой офис, полный разных сотрудников (компонентов). Каждый из сотрудников решает свою задачу, но иногда кто-то ошибается. Чтобы не закрывать весь офис из-за ошибок одного сотрудника, нам нужен метод для перехвата таких ситуаций. Именно этим и займется наш HOC.

HOC для обработки ошибок позволяет оборачивать компоненты и добавлять им интерфейс обработки исключений. Если внутри компонента что-то пойдет не так (например, ошибка JavaScript или ошибка API), этот HOC сможет поймать ошибку, показать дружелюбное сообщение пользователю и при необходимости отправить данные об ошибке в систему мониторинга.

Основы создания HOC

Начнем с создания простого компонента высшего порядка, который поможет нам обработать ошибки. Мы будем использовать встроенный метод React под названием componentDidCatch, который доступен в Error Boundary (границе ошибок). Помните, что Error Boundary работает только с ошибками в процессе рендера, в методах жизненного цикла и конструкторах дочерних компонентов.

Базовая реализация HOC

Давайте создадим HOC, который добавляет функциональность обработки ошибок:

import React, { Component, ComponentType } from 'react';

// Интерфейс для состояния нашего HOC
interface ErrorBoundaryState {
  hasError: boolean;
  errorMessage: string;
}

// Функция HOC принимает компонент и возвращает новый компонент с обработкой ошибок
function withErrorBoundary<P>(WrappedComponent: ComponentType<P>) {
  return class ErrorBoundary extends Component<P, ErrorBoundaryState> {
    constructor(props: P) {
      super(props);
      this.state = {
        hasError: false,
        errorMessage: '',
      };
    }

    // Метод ловит ошибки в дочерних компонентах
    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
      console.error("Caught error:", error, errorInfo);
      this.setState({ hasError: true, errorMessage: error.message });
    }

    render() {
      const { hasError, errorMessage } = this.state;

      if (hasError) {
        // Показываем пользовательский интерфейс для обработки ошибки
        return <h1>Что-то пошло не так: {errorMessage}</h1>;
      }

      // Если ошибок нет, рендерим оборачиваемый компонент
      return <WrappedComponent {...this.props} />;
    }
  };
}

export default withErrorBoundary;

Разберем код

  1. Типизация пропсов: мы принимаем компонент с неизвестными пропсами P (generic тип), чтобы наш HOC был универсальным.
  2. Состояние HOC: состояние хранит флаг hasError и сообщение об ошибке. Это позволяет нам отображать ошибку при её возникновении.
  3. Метод componentDidCatch: этот метод вызывает React в случае ошибки в дочернем компоненте. Мы используем его для обновления состояния и логгирования ошибки в консоли.
  4. Рендеринг: если ошибка произошла, отображается сообщение; если нет, оборачиваемый компонент рендерится как обычно.

Пример использования HOC

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

Компонент с ошибкой

const BuggyComponent: React.FC = () => {
  throw new Error("Ой! Что-то пошло не так...");
  return <div>Этот текст вы никогда не увидите</div>;
};

Оборачиваем компонент

import React from 'react';
import withErrorBoundary from './withErrorBoundary';

const SafeComponent = withErrorBoundary(BuggyComponent);

const App: React.FC = () => {
  return (
    <div>
      <h1>Пример обработки ошибок</h1>
      <SafeComponent />
    </div>
  );
};

export default App;

Когда вы запустите приложение, вместо того чтобы увидеть экран смерти, вы получите пользовательское сообщение: "Что-то пошло не так...".

Улучшаем HOC: передача пользовательского интерфейса

Иногда мы хотим, чтобы при ошибке отображалось не дефолтное сообщение, а кастомный компонент (например, кнопка "Попробовать снова" или сообщение о техобслуживании).

Обновляем HOC

Добавим возможность передавать компонент для отображения ошибок:

interface ErrorBoundaryProps {
  fallback?: React.ReactNode;
}

function withErrorBoundary<P>(
  WrappedComponent: ComponentType<P>,
  options?: ErrorBoundaryProps
) {
  return class ErrorBoundary extends Component<P, ErrorBoundaryState> {
    constructor(props: P) {
      super(props);
      this.state = {
        hasError: false,
        errorMessage: '',
      };
    }

    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
      console.error("Caught error:", error, errorInfo);
      this.setState({ hasError: true, errorMessage: error.message });
    }

    render() {
      const { hasError, errorMessage } = this.state;

      if (hasError) {
        return options?.fallback || <h1>Что-то пошло не так: {errorMessage}</h1>;
      }

      return <WrappedComponent {...this.props} />;
    }
  };
}

Как использовать?

Теперь мы можем передать компонент для отображения ошибок:

const CustomErrorFallback = () => (
  <div style={{ color: 'red' }}>
    <h2>Oops! Это ошибка.</h2>
    <button onClick={() => window.location.reload()}>Перезагрузить страницу</button>
</div>
);

const SafeComponentWithCustomFallback = withErrorBoundary(BuggyComponent, {
fallback: <CustomErrorFallback />,
});

Типичные ошибки и особенности

При создании HOC для обработки ошибок необходимо помнить несколько важных моментов:

  1. Error Boundary не ловит ошибки в обработчиках событий, асинхронных функциях или цепочках промисов. Чтобы поймать такие ошибки, используйте try-catch в асинхронных функциях или добавляйте обработчики ошибок на уровне Promise.
  2. Если вы передаете большой объем пропсов, убедитесь, что их типизация корректно обрабатывается. Используя P как generic тип, вы минимизируете риск ошибок.
  3. Никогда не злоупотребляйте Error Boundary. Это инструмент для улучшения пользовательского опыта, а не для "маскировки" проблем в вашем коде.

Этот HOC можно использовать для создания более надежных приложений. Например, вы можете оборачивать компоненты, которые работают с данными из API. Если произойдет ошибка, пользователь увидит понятное сообщение вместо "крутящегося колеса" до бесконечности. Подобные компоненты помогут вам развить привычку писать приложения, которые "не боятся" проблем и умеют их элегантно обрабатывать.

1
Задача
Модуль 3: React, 4 уровень, 1 лекция
Недоступна
Простая обработка ошибок с использованием HOC
Простая обработка ошибок с использованием HOC
1
Задача
Модуль 3: React, 4 уровень, 1 лекция
Недоступна
Обработка ошибок с кастомным интерфейсом через HOC
Обработка ошибок с кастомным интерфейсом через HOC
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ