Головна / Статті / Надсилання даних за допомогою RTK Query: практичний посібник з мутаціями

Надсилання даних за допомогою RTK Query: практичний посібник з мутаціями

Дізнайтеся, як використовувати builder.mutation() у RTK Query для надсилання запитів типу POST, керування станами завантаження та помилок, а також створення функціонального компонента форми.

1875 слів

Вступ

Раніше ми розглядали, як налаштувати 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 Додавання нових даних
Створити користувача PUT Перезаписати існуючий ресурс Замінити запис користувача PATCH Змінити частину ресурсу Змінити ім’я користувача DELETE Видалити дані Видалити користувача

Цей посібник присвятований методу 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 безпосередньо з форми React.
  • Керуйте станами завантаження, успіху та помилок без необхідності писати власні шаблони коду.
  • Розрізняйте запити та мутації.
  • Застосовуйте ефективні практики для створення API-інтерфейсів, які легко підтримувати.
  • Ця сама схема постійно використовується у продакшн-додатках — під час реєстрації користувачів, автентифікації, публікації записів у блогу, оформлення замовлень та безлічі інших сценаріїв створення даних.

    Що далі?

    Після того, як ви опанували запити типу POST, наступним логічним кроком є навчання того, як оновлювати та видаляти існуючі записи.

    У майбутньому посібнику буде розглянуто:

    • Оновлення записів за допомогою запитів PUT та PATCH.
    • Видалення записів за допомогою запитів DELETE.
    • Передача динамічних ID до кінцевих точок мутацій.
    • Анулювання кешованих даних для автоматичного оновлення інтерфейсу.
    • Використання тегів — providesTags та invalidatesTags — для підтримки синхронності всього без необхідності ручного оновлення даних.

    До кінця цього посібника ви зможете створити повноцінний додаток CRUD, використовуючи готові до експлуатації шаблони RTK Query.

    Пов’язана література