Что такое мутация?
Если запросы (queries) в GraphQL можно сравнить с чтением данных из базы, то мутации (mutations) — это операции записи, добавления, обновления или удаления данных. Они вносят изменения на сервере. В отличие от запросов, мутации всегда выполняются последовательно (даже если вы отправляете несколько мутаций одновременно).
Мутации пишутся почти так же, как и запросы. Основное отличие — ключевое слово mutation. Вот пример базового синтаксиса:
mutation {
addUser(name: "Alice", email: "alice@example.com") {
id
name
email
}
}
В этом примере мы добавляем пользователя с именем "Alice". В ответ сервер возвращает id, name и email нового пользователя.
Зачем это нужно? Мутации позволяют клиенту изменять состояние данных на сервере, будь то добавление новой записи в базу данных, обновление профиля пользователя или удаление данных.
Реализация мутаций с использованием Apollo Client
Теперь, когда у нас есть представление о том, что такое мутации, давайте окунёмся в код. Для работы с мутациями в Apollo Client используется хук useMutation.
Если вы ещё не настроили Apollo Client, сделайте это, следуя инструкциям из предыдущих лекций. Убедитесь, что ваш клиент настроен и подключён к GraphQL серверу.
Для демонстрации мы будем работать с мутацией, которая добавляет пользователя. Вот пример исходного GraphQL:
mutation AddUser($name: String!, $email: String!) {
addUser(name: $name, email: $email) {
id
name
email
}
}
Использование useMutation в React-компоненте
Создаем мутацию в React:
import React, { useState } from 'react';
import { gql, useMutation } from '@apollo/client';
// Определяем GraphQL-мутaцию
const ADD_USER = gql`
mutation AddUser($name: String!, $email: String!) {
addUser(name: $name, email: $email) {
id
name
email
}
}
`;
interface User {
id: string;
name: string;
email: string;
}
const AddUserForm: React.FC = () => {
const [name, setName] = useState<string>('');
const [email, setEmail] = useState<string>('');
// Используем хук useMutation
const [addUser, { data, loading, error }] = useMutation<{ addUser: User }>(ADD_USER);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const result = await addUser({ variables: { name, email } });
console.log('New user added:', result.data?.addUser);
} catch (err) {
console.error('Error adding user:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name: </label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div>
<label>Email: </label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<button type="submit" disabled={loading}>
{loading ? 'Adding...' : 'Add User'}
</button>
{error && <p style={{ color: 'red' }}>Error: {error.message}</p>}
{data && (
<p style={{ color: 'green' }}>
User added: {data.addUser.name} ({data.addUser.email})
</p>
)}
</form>
);
};
export default AddUserForm;
Что здесь происходит?
- Мы определяем мутaцию
ADD_USERс переменными$nameи$email. - Используем хук
useMutation, чтобы отправить запрос на сервер. - Обрабатываем ввод пользователя через
useState. - При отправке формы вызываем переданную функцией
addUser, передавая значения переменных.
Обработка результатов мутаций
После выполнения мутации вы можете обновить интерфейс или использовать возвращённые данные. Рассмотрим три основные задачи:
1. Управление состоянием после мутации
В приведённом выше примере мутация обновляет интерфейс, показывая сообщение об успехе. Вы можете использовать onCompleted в useMutation, чтобы передать дополнительные действия после успеха:
const [addUser] = useMutation(ADD_USER, {
onCompleted: (data) => {
console.log('User successfully added:', data.addUser);
},
});
2. Обновление кэша Apollo
Иногда после выполнения мутации нужно обновить локальный кэш Apollo, чтобы данные UI отображались актуально. Например, если мы добавляем пользователя в список:
const [addUser] = useMutation(ADD_USER, {
update: (cache, { data }) => {
const newUser = data?.addUser;
if (newUser) {
cache.modify({
fields: {
users(existingUsers = []) {
return [...existingUsers, newUser];
},
},
});
}
},
});
Беседа с Apollo Cache напоминает диалог с вашим начальником: если вы объясните, что хотите, грамотно – получите результат без проблем.
3. Обработка ошибок
Для обработки ошибок используйте error из возвращаемого объекта:
if (error) {
alert(`Could not add user: ${error.message}`);
}
Практическое применение
Мутации невероятно полезны для любых операций, связанных с изменением данных. Например:
- Добавление нового пользователя, продукта или комментария.
- Обновление профиля пользователя.
- Удаление ненужных данных.
Такая гибкость особенно полезна в сложных проектах, где клиенту нужно динамически обновлять интерфейс в ответ на действия пользователя. Это также часто встречается в e-commerce и социальных платформах.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ