Главная / Статьи / Отправка данных с помощью 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.
  • Проверяйте введенный пользователем текст перед отправкой на сервер.
  • Используйте метод unwrap(), если вы предпочитаете обрабатывать случаи успеха и неудачи с помощью блока try...catch внутри своих компонентов.
  • Основные выводы

    Пройдя этот руководство, вы узнали, как:

    • Настроить мутацию с помощью builder.mutation().
    • Подключить конечную точку POST внутри API-сегмента.
    • Отправлять JSON-данные на сервис бэкенда.
    • Используйте автогенерируемый хук useAddUserMutation().
    • Отправляйте запросы типа POST непосредственно из формы React.
    • Управляйте состояниями загрузки, успеха и ошибок без необходимости писать ручной шаблон кода.
    • Разделяйте запросы к данным и операции с ними.
    • Применяйте проверенные практики для создания удобных в обслуживании интерфейсов API.

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

    Что дальше?

    После того как вы освоили запросы типа POST, следующим логичным шагом будет изучение способов обновления и удаления существующих записей.

    В предстоящем руководстве будет рассмотрено:

    • Обновление записей с помощью запросов PUT и PATCH.
    • Удаление записей с помощью запросов DELETE.
  • Передача динамических ID в концовки мутаций.
  • Аннулирование кэшированных данных для автоматического обновления интерфейса.
  • Использование тегов — providesTags и invalidatesTags — для синхронизации всего без необходимости вручную перезагружать данные.
  • К моменту завершения этого руководства вы сможете создать полноценное приложение CRUD, используя готовые к производству шаблоны RTK Query.

    Связанные материалы