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

Обработка ошибок и управление состоянием загрузки

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

Типы ошибок в GraphQL

В GraphQL можно столкнуться с тремя основными типами ошибок:

  1. Ошибки запроса (GraphQL Errors) — возникают, если сервер GraphQL вернул данные с ошибкой (например, вместо products, которые пользователь запросил, вернулся null с сообщением "Unauthorized").
  2. Сетевые ошибки (Network Errors) — появляются, если запрос не смог вообще достучаться до сервера, например, из-за сбоя сети или недоступности сервера.
  3. Локальные ошибки (Local Errors) — это ошибки, возникающие в вашем приложении, скажем, из-за неправильной обработки данных или опечатки. Да-да, ошибки в коде — наше всё!

Управление состоянием загрузки и ошибок с Apollo Client

Apollo Client реализует встроенные механизмы для управления состояниями загрузки и ошибок, которые возвращаются из хуков useQuery и useMutation. Они дают вам полное представление о том, что происходит с запросами, напрямую через возвращаемые значения.

Пример состояния загрузки

Создаём запрос с использованием useQuery:

import { useQuery, gql } from '@apollo/client';

const GET_PRODUCTS = gql`
  query GetProducts {
    products {
      id
      name
      price
    }
  }
`;

const ProductList: React.FC = () => {
  const { loading, error, data } = useQuery(GET_PRODUCTS);

  if (loading) return <p>Загрузка...</p>;
  if (error) return <p>Ошибка: {error.message}</p>;

  return (
    <ul>
      {data.products.map((product: { id: string; name: string; price: number }) => (
        <li key={product.id}>
          {product.name} - ${product.price}
        </li>
      ))}
    </ul>
  );
};

Обратите внимание на три ключевых состояния:

  1. loadingtrue, пока данные загружаются.
  2. error — содержит объект ошибки, если запрос завершился неудачно.
  3. data — содержит ответ сервера, если запрос прошёл успешно.

Вот так легко мы добавили индикатор загрузки и обработку ошибок.

Более изящная обработка ошибок

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

if (loading) {
  return <p>Подождите, грузим ваши продукты...</p>;
}

if (error) {
  return (
    <div>
      <h2>Что-то пошло не так 😢</h2>
      <p>Подробности: {error.message}</p>
      <button onClick={() => window.location.reload()}>Попробовать снова</button>
    </div>
  );
}

Если ошибка всё же произошла, мы предлагаем пользователю кнопку "Попробовать снова".

Локализация обработки ошибок

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

Создание пользовательского хука для обработки ошибок

import { ApolloError } from '@apollo/client';

const useHandleError = (error: ApolloError | undefined) => {
  if (!error) return null;

  // Пример: Логирование ошибок
  console.error('GraphQL Error:', error);

  // Можно добавить кастомную обработку
  if (error.networkError) {
    return 'Проблема с соединением. Проверьте интернет.';
  }

  if (error.graphQLErrors.length > 0) {
    return error.graphQLErrors[0].message;
  }

  return 'Неизвестная ошибка';
};

export default useHandleError;

Теперь вы можете использовать этот хук в вашем компоненте:

const errorMessage = useHandleError(error);

if (errorMessage) {
  return <p>{errorMessage}</p>;
}

Управление состоянием загрузки

Индикаторы загрузки помогают создать ощущение "живого" приложения. Но они должны быть не только информативными, но и ненавязчивыми.

Можно использовать готовую библиотеку (например, react-spinners) или создать свой простой компонент для отображения спиннера:

const Spinner: React.FC = () => (
  <div className="spinner">
    <div className="loader" />
    <style jsx>{`
      .spinner {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100%;
      }
      .loader {
        border: 4px solid #f3f3f3;
        border-top: 4px solid #3498db;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        animation: spin 1s linear infinite;
      }
      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    `}</style>
  </div>
);

Используйте его во время загрузки:

if (loading) {
  return <Spinner />;
}

Практическое применение

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

const LoadingErrorWrapper: React.FC<{ loading: boolean; error: ApolloError | undefined }> = ({ loading, error, children }) => {
  const errorMessage = useHandleError(error);

  if (loading) {
    return <Spinner />;
  }

  if (errorMessage) {
    return <p>{errorMessage}</p>;
  }

  return <>{children}</>;
};

Используем наш компонент:

<LoadingErrorWrapper loading={loading} error={error}>
  <ul>
    {data.products.map((product: { id: string; name: string; price: number }) => (
      <li key={product.id}>
        {product.name} - ${product.price}
      </li>
    ))}
  </ul>
</LoadingErrorWrapper>

Теперь управление состояниями загрузки и ошибок стало максимально простым!

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

  1. Не обрабатывать все состояния (например, loading есть, а error забыли).
  2. Показывать пользователю незавершённую загрузку, не добавив индикатор.
  3. Оставлять ошибки без перевода/локализации: "Cannot fetch data" для пользователя выглядит странно, если ваш интерфейс не на английском.
  4. Неочевидные действия: пользователю предлагается что угодно, но не кнопка для повторной попытки.

Итак, теперь вы знаете, как создавать отзывчивые и устойчивые к ошибкам интерфейсы. Как разработчик, ваше приложение стало умнее и лучше взаимодействует с пользователем!

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