JavaRush /Курсы /Модуль 3: React /Использование хуков Apollo (useQuery, useMutation) для ра...

Использование хуков Apollo (useQuery, useMutation) для работы с GraphQL

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

Введение

В React мы очень любим хуки. Почему? Потому что они позволяют нам писать код, который легко читается, переиспользуется и тестируется. Apollo Client поддерживает эту философию, предоставляя хуки useQuery и useMutation для удобной работы с GraphQL-запросами и мутациями. Это делает их использование естественным для любого React-разработчика.

Сегодня мы будем:

  1. Узнавать, как useQuery помогает нам запрашивать данные.
  2. Использовать useMutation для изменения данных на сервере.
  3. Обсуждать обработку состояний загрузки, ошибок и успешного получения данных.
  4. Рассматривать примеры и строить приложение, которое активно использует GraphQL.

Ну что, готовы? Сейчас начнется самое интересное.

Хук useQuery: запрашиваем данные

Хук useQuery позволяет вам отправлять запросы на сервер GraphQL и получать данные. Всё просто: вы передаете ему GraphQL-запрос, а в ответ получаете объект со статусами загрузки, ошибками и данными.

Пример:

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

// Определяем GraphQL-запрос
const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
      email
    }
  }
`;

const UsersList: React.FC = () => {
  // Используем хук useQuery
  const { loading, error, data } = useQuery(GET_USERS);

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

  return (
    <ul>
      {data.users.map((user: { id: string; name: string; email: string }) => (
        <li key={user.id}>
          {user.name} ({user.email})
        </li>
      ))}
    </ul>
  );
};

export default UsersList;

Как это работает?

  1. Создаём запрос через gql: сначала описываем GraphQL-запрос (в данном случае GET_USERS).
  2. Используем useQuery: передаем запрос в хук, и он автоматически отправляет его на сервер.
  3. Обрабатываем состояния:
    • loading: когда данные загружаются.
    • error: когда что-то пошло не так.
    • data: когда данные успешно загружены.

Типизация useQuery с TypeScript

Хороший код — это типизированный код. Давайте научимся типизировать результаты запроса.

Шаг 1: Создаём интерфейсы

interface User {
  id: string;
  name: string;
  email: string;
}

interface UsersData {
  users: User[];
}

Шаг 2: Передаём типы в useQuery

const { loading, error, data } = useQuery<UsersData>(GET_USERS);

Теперь TypeScript подскажет нам, какие свойства доступны в data, что значительно снижает риск ошибок.

Хук useMutation: изменяем данные

Хук useMutation нужен для выполнения мутаций. Если useQuery — это "читать данные", то useMutation — это "менять данные" (добавлять, удалять, обновлять).

Пример:

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

// Определяем мутацию
const ADD_USER = gql`
  mutation AddUser($name: String!, $email: String!) {
    addUser(name: $name, email: $email) {
      id
      name
      email
    }
  }
`;

const AddUserForm: React.FC = () => {
  const [addUser, { data, loading, error }] = useMutation(ADD_USER);

  const handleSubmit = async () => {
    try {
      const result = await addUser({ variables: { name: 'John', email: 'john@doe.com' } });
      console.log('Добавлен пользователь:', result.data.addUser);
    } catch (e) {
      console.error('Ошибка:', e);
    }
  };

  return (
    <div>
      {loading && <p>Добавление пользователя...</p>}
      {error && <p>Ошибка: {error.message}</p>}
      <button onClick={handleSubmit}>Добавить пользователя</button>
    </div>
  );
};

export default AddUserForm;

Как это работает?

  1. Определяем мутацию: описание GraphQL-запроса ADD_USER для добавления пользователя.
  2. Получаем функцию addUser через useMutation: она отправляет запрос на сервер.
  3. Передаём переменные: используем параметр variables для передачи данных в сервер.

Типизация useMutation с TypeScript

Вы наверняка догадались: типы тут тоже спасают нас от бед.

Шаг 1: Создаём интерфейсы

interface AddUserVariables {
  name: string;
  email: string;
}

interface AddUserResponse {
  addUser: {
    id: string;
    name: string;
    email: string;
  };
}

Шаг 2: Передаём типы в useMutation

const [addUser] = useMutation<AddUserResponse, AddUserVariables>(ADD_USER);

Теперь TypeScript проверяет и переменные, и структуру ответа!

Обработка ошибок и оптимизация

Работа с GraphQL не всегда проходит гладко. Вот несколько советов:

  1. Обрабатывайте ошибки в хуках. Используйте error из useQuery и useMutation, чтобы показать пользователю, если что-то пошло не так.

  2. Используйте состояние загрузки. Показывайте индикаторы загрузки loading, чтобы интерфейс оставался отзывчивым.

  3. Оптимизируйте кэш. После выполнения мутаций обновляйте кэш, чтобы изменения сразу отобразились в UI:

    const [addUser] = useMutation(ADD_USER, {
      update(cache, { data }) {
        const existing = cache.readQuery<UsersData>({ query: GET_USERS });
        if (existing && data) {
          cache.writeQuery({
            query: GET_USERS,
            data: {
              users: [...existing.users, data.addUser],
            },
          });
        }
      },
    });
    

Создаём форму для добавления пользователей

Давайте свяжем useQuery и useMutation в одно приложение.

Код:

const App: React.FC = () => {
  return (
    <ApolloProvider client={client}>
      <h1>Список пользователей</h1>
      <UsersList />
      <h2>Добавить пользователя</h2>
      <AddUserForm />
    </ApolloProvider>
  );
};

Теперь наше приложение умеет как получать данные с помощью useQuery, так и изменять их с помощью useMutation.

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