Надсилання даних за допомогою RTK Query: практичний посібник з мутаціями
Дізнайтеся, як використовувати builder.mutation() у RTK Query для надсилання запитів типу POST, керування станами завантаження та помилок, а також створення функціонального компонента форми.
Вступ
Раніше ми розглядали, як налаштувати Redux Toolkit Query (RTK Query) та виконувати операції зчитування за допомогою builder.query(). Це дозволило нам отримувати дані з API та відображати їх у додатку на React без необхідності реалізації власних функцій useEffect(), useState() чи логіки отримання даних.
Проте зчитування даних — це лише половина справи під час роботи з API. Більшості додатків також потрібні способи додавання, зміни чи видалення записів на сервері.
Розгляньмо кілька поширених сценаріїв:
- Форма реєстрації надсилає дані нового облікового запису.
- Екран входу надсилає облікові дані для перевірки.
- Платформа для блогінгу публікує нові статті.
- Інтернет-магазин оформлює нові замовлення.
- Додаток для списку завдань зберігає ново додані завдання.
Кожна з цих дій передає інформацію від клієнта до сервера, і зазвичай це відбувається через запит HTTP POST.
RTK Query не розглядає запити POST як звичайні запити — він розглядає їх як мутації.
У цій статті детально розглядається процес надсилання даних за допомогою builder.mutation(). Ми розберемо кожну частину коду та кожне налаштування, щоб ви зрозуміли не лише те, що потрібно ввести, а й чому кожна частина має значення.
Розуміння методів HTTP
Перш ніж переходити до коду, корисно ознайомитися з різними дієсловами HTTP та їх призначенням.
Типовий REST API надає кілька операцій:
| Метод | Призначення | Приклад |
|---|---|---|
| GET | Читання даних | Отримання всіх користувачів |
| POST | Додавання нових даних |
Цей посібник присвятований методу POST, який використовується для створення нових ресурсів на сервері.
Чому POST не використовує builder.query()?
Це поширена причина плутанини серед початківців.
Якщо builder.query() може отримувати дані, чому та сама функція не може надсилати дані на сервер?
Причина криється у призначенні кожного інструменту.
Запити
Запити існують для отримання інформації.
Типові приклади:
- Отримати користувачів
- Отримати товари
- Отримати замовлення
- Отримати публікації
Оскільки одні й ті самі дані можуть запитуватися багаторазово, запити автоматично кешують свої результати.
Мутації
Мутації існують для зміни даних.
Типові приклади:
- Створення користувача
- Оновлення користувача
- Видалення користувача
- Увійшти
- Реєстрація
Мутація сигналізує серверу про необхідність змін.
Саме через цю відмінність RTK Query обробляє мутації окремо від звичайних запитів.
Що ми збираємося створити
Ми створимо базову форму, яка надсилатиме нового користувача на сервер.
Цільовий кінцевий пункт —:
https://jsonplaceholder.typicode.com/users
А вантаж, надісланий у тілі запиту, буде виглядати так:
{
"name": "John Doe",
"email": "john@example.com"
}
Структура проекту
src
│
├── app
│ └── store.js
│
├── services
│ └── api.js
│
├── components
│ └── AddUser.jsx
│
├── App.jsx
│
└── main.jsx
Конфігурація сховища Redux залишається такою, якою була раніше. Усе, що нам потрібно додати, — це кінцева точка для мутацій та компонент, який обробляє надсилання форми.
Крок 1 — Створення кінцевої точки для мутацій
Відкрийте файл API-сервісу:
src/services/api.js
Потім додайте визначення нової кінцевої точки всередину об’єкта endpoints.
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
export const api = createApi({
reducerPath: "api", baseQuery: fetchBaseQuery({
baseUrl: "https://jsonplaceholder.typicode.com/",
}), endpoints: (builder) => ({ addUser: builder.mutation({ query: (newUser) => ({
url: "users",
method: "POST",
body: newUser,
}), }), }),});export const {
useAddUserMutation,
} = api;
Розгляньмо цей код рядок за рядком.
Розуміння builder.mutation()
addUser: builder.mutation({
Хоча builder.query() призначений для отримання даних, builder.mutation() використовується тоді, коли потрібно щось змінити на сервері.
Поширені сценарії його використання:
- Створення користувачів
- Реєстрація облікових записів
- Увійшення
- Оновлення продуктів
- Видалення записів
Кожного разу, коли ваш додаток записує або змінює дані на бекенді, мутація є правильним інструментом для цього.
Розуміння query()
query: (newUser) => ({
Ця функція отримує будь-які дані, які ви передаєте їй з коду React.
Наприклад, якщо ви відправляєте:
addUser({
name: "John",
email: "john@example.com",
});
тоді параметр під назвою
newUser
буде містити:
{
name: "John",
email: "john@example.com"
}
Саме цей об’єкт надсилається як тіло запиту.
Розуміння URL
url: "users",
Оскільки базова URL налаштована як:
https://jsonplaceholder.typicode.com/
RTK Query автоматично поєднує їх у:
https://jsonplaceholder.typicode.com/users
тож вам ніколи не доводиться самостійно писати повну адресу.
Розуміння методу
method: "POST",
Цей рядок прямо вказує RTK Query на необхідність надсилання запиту типу POST. Якщо його пропустити, запит за замовчуванням буде типу GET.
Розуміння тіла запиту
body: newUser,
Усе, що зберігається в newUser, передається як вміст запиту, наприклад:
{
"name": "John",
"email": "john@example.com"
}
Сервер отримує цей об’єкт саме у тому вигляді, у якому він був створений.
Крок 2 — Експорт генерованого хука
export const {
useAddUserMutation,
} = api;
Так само, як запити створюють автоматично генерований хук, наприклад
useGetUsersQuery()
мутації також автоматично створюють власні хуки:
useAddUserMutation()
Ви ніколи не пишете цей хук вручну — RTK Query створює його для вас на основі назви кінцевої точки.
Крок 3 — Створення компонента React
Створіть новий файл:
src/components/AddUser.jsx
і додайте цей код:
import { useState } from "react";
import { useAddUserMutation } from "../services/api";const AddUser = () => { const [name, setName] = useState("");
const [email, setEmail] = useState(""); const [
addUser,
{
isLoading,
isSuccess,
error,
},
] = useAddUserMutation(); const handleSubmit = async (e) => { e.preventDefault(); await addUser({
name,
email,
}); setName("");
setEmail(""); }; return (
<form onSubmit={handleSubmit}> <input
type="text"
placeholder="Enter Name"
value={name}
onChange={(e) => setName(e.target.value)}
/> <input
type="email"
placeholder="Enter Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/> <button type="submit">
Add User
</button> {isLoading && <p>Saving...</p>} {isSuccess && <p>User Added Successfully.</p>} {error && <p>Something went wrong.</p>} </form>
);};export default AddUser;
Давайте розберемо, що тут відбувається.
Розуміння useAddUserMutation()
const [
addUser,
{
isLoading,
isSuccess,
error,
},
] = useAddUserMutation();
На відміну від хуків запитів, хуки мутацій повертають масив замість об’єкта. Перший елемент:
addUser
Це функція, яку ви викликаєте для ініціювання запиту, тоді як другий елемент — це об’єкт, що містить корисну інформацію про статус цього запиту.
Розуміння addUser()
await addUser({
name,
email,
});
Виклик цієї функції відправляє запит у такому форматі:
POST /users
З навантаженим JSON-даними такої структури:
{
"name": "John",
"email": "john@example.com"
}
На серверній частині ці дані використовуються для створення абсолютно нової запису користувача.
Розуміння станів змін
Окрім функції ініціювання, RTK Query надає кілька прапорців статусу, які описують те, що відбувається з запитом.
isLoading
isLoading
Цей прапорець стає true, поки зміна виконується, тому його можна використовувати для призупинення роботи кнопки надсилання чи відображення індикатора завантаження до отримання відповіді.
isSuccess
isSuccess
Як тільки запит виконується без помилок, цей значення стає true, що дає чіткий сигнал для відображення повідомлення про підтвердження або переходу користувача в інше місце.
error
error
Якщо сервер відповідає про помилку, деталі потрапляють сюди, що дозволяє відобразити зрозумілу помилку замість нефункціонального інтерфейсу.
Крок 4 — Відображення компонента
Відкрийте основний файл програми:
src/App.jsx
і замініть його вміст на наступний:
import AddUser from "./components/AddUser";
function App() {
return <AddUser />;
}export default App;
Потім запустіть розробницький сервер:
npm run dev
Заповніть поля форми та натисніть Add User — RTK Query самостійно надсилатиме запит POST.
Повний процес запиту
Ось короткий огляд того, що відбувається насправді, від надсилання форми до оновлення стану:
User Fills Form
│
▼
Clicks Submit
│
▼
addUser()
│
▼
Generated Mutation Hook
│
▼
RTK Query
│
▼
fetchBaseQuery()
│
▼
POST Request
│
▼
Server Response
│
▼
Mutation State Updates
│
▼
React Re-renders
Зверніть увагу на все, чого бракує в цьому алгоритмі:
fetch()axios.post()useEffect()- Ручний відстежуваний стан завантаження
- Ручний відстежуваний стан помилок
RTK Query самостійно керує всім цим у фоновому режимі.
builder.query() проти builder.mutation()
Дуже важливо знати, коли використовувати кожен із цих методів конструктора.
builder.query() призначений для отримання даних, зазвичай через запити типу GET, і створює гаки на кшталт useGetUsersQuery(), які виконуються автоматично щойно компонент відображається. Натомість builder.mutation() призначений для зміни даних за допомогою методів типу POST, PUT, PATCH чи DELETE. Він створює гаки на кшталт useAddUserMutation(), які виконуються лише тоді, коли ви прямо викликаєте функцію-тригер, а не під час відображення компонента. Коротко кажучи, запити використовуються для читання, а мутації — для створення, оновлення чи видалення.
Вибір правильного інструменту для кожної задачі забезпечує послідовність логіки API та полегшує її розуміння.
Найкращі практики
Пам’ятайте про ці рекомендації щоразу, коли створюєте функціонал POST за допомогою RTK Query:
- Використовуйте
builder.mutation()кожного разу, коли операція змінює дані на сервері.
isLoading, isSuccess та error, щоб інтерфейс відповідав та надавав достатньо інформації.addUser, createPost чи registerUser.try...catch у своїх компонентах, розгляньте використання unwrap().Основні висновки
Пройшовши цей посібник, ви дізналися, як:
- Налаштувати мутацію за допомогою
builder.mutation(). - Під’єднати кінцеву точку POST у складі API slice.
- Надсилати JSON-дані до сервісу бекенду.
useAddUserMutation().Ця сама схема постійно використовується у продакшн-додатках — під час реєстрації користувачів, автентифікації, публікації записів у блогу, оформлення замовлень та безлічі інших сценаріїв створення даних.
Що далі?
Після того, як ви опанували запити типу POST, наступним логічним кроком є навчання того, як оновлювати та видаляти існуючі записи.
У майбутньому посібнику буде розглянуто:
- Оновлення записів за допомогою запитів PUT та PATCH.
- Видалення записів за допомогою запитів DELETE.
- Передача динамічних ID до кінцевих точок мутацій.
- Анулювання кешованих даних для автоматичного оновлення інтерфейсу.
- Використання тегів —
providesTagsтаinvalidatesTags— для підтримки синхронності всього без необхідності ручного оновлення даних.
До кінця цього посібника ви зможете створити повноцінний додаток CRUD, використовуючи готові до експлуатації шаблони RTK Query.
Пов’язана література
- Зміни за замовчуванням у TypeScript 6.0: практичний посібник з міграції — Дізнайтеся, які дев’ять параметрів компілятора TypeScript 6.0 змінилися, як налаштувати tsconfig для 2026 року та як підготувати кодові бази до TypeScript 7, заснованого на Go.
- Стандарти повного стеку JavaScript у 2026 році: TypeScript, RSC та інше — Пояснює, чому TypeScript, React Server Components та більш ефективний підхід до керування станом стали стандартними інструментами для команд, які працюють з JavaScript у 2026 році.