Envío de datos con consulta RTK: Una guía práctica sobre mutaciones
Aprenda cómo utilizar builder.mutation() en RTK Query para enviar solicitudes POST, gestionar los estados de carga y error, y crear un componente de formulario funcional.
Introducción
Anteriormente explicamos cómo configurar Redux Toolkit Query (RTK Query) y ejecutar operaciones de lectura con builder.query(). Esto nos permitió obtener datos de una API y mostrarlos dentro de una aplicación React sin tener que implementar manualmente useEffect(), useState() o lógica de solicitud personalizada.
No obstante, leer datos es solo la mitad de la historia al trabajar con APIs. La mayoría de las aplicaciones también necesitan formas de agregar, modificar o eliminar registros en el servidor.
Considere algunos escenarios comunes:
- Un formulario de registro envía los detalles de una nueva cuenta.
- Una pantalla de inicio de sesión envía las credenciales para su verificación.
- Una plataforma de blogs publica nuevos artículos.
- Una tienda en línea realiza nuevos pedidos.
- Una aplicación de tareas guarda las tareas recién añadidas.
Cada una de estas acciones envía información desde el cliente hacia el servidor, y eso se hace normalmente a través de una solicitud HTTP POST.
RTK Query no trata las llamadas POST como consultas; las considera mutaciones.
Este artículo explica cómo enviar datos con builder.mutation(). Desglosaremos cada parte del código y cada configuración para que entienda no solo qué escribir, sino también por qué es importante cada elemento.
Comprensión de los métodos HTTP
Antes de adentrarnos en el código, es útil revisar los diferentes verbos HTTP y su propósito.
Una API REST típica expone varias operaciones:
| Método | Propósito | Ejemplo |
|---|---|---|
| GET | Leer datos | Obtener a todos los usuarios |
| POST | Añadir nuevos datos |
Esta guía se centra en POST, el método utilizado para crear nuevos recursos en un servidor.
¿Por qué POST no utiliza builder.query()?
Este es un punto de confusión común entre los principiantes.
Si builder.query() puede recuperar datos, ¿por qué la misma función no puede enviar datos al servidor?
La razón se debe a para qué fue diseñado cada herramienta.
Consultas
Las consultas existen para obtener información.
Ejemplos típicos:
- Obtener usuarios
- Obtener productos
- Obtener pedidos
- Obtener publicaciones
Dado que los mismos datos pueden solicitarse repetidamente, las consultas almacenan automáticamente sus resultados en caché.
Mutaciones
Las mutaciones existen para modificar datos.
Ejemplos típicos:
- Crear usuario
- Actualizar usuario
- Borrar usuario
- Iniciar sesión
- Registrarse
Una mutación indica al servidor que algo necesita cambiar.
Esa distinción es la razón por la cual RTK Query maneja las mutaciones de forma separada de las consultas.
Qué vamos a construir
Vamos a crear un formulario básico que envíe un nuevo usuario al servidor.
El endpoint de destino es:
https://jsonplaceholder.typicode.com/users
Y la carga útil enviada en el cuerpo de la solicitud tendrá este aspecto:
{
"name": "John Doe",
"email": "john@example.com"
}
Estructura del proyecto
src
│
├── app
│ └── store.js
│
├── services
│ └── api.js
│
├── components
│ └── AddUser.jsx
│
├── App.jsx
│
└── main.jsx
La configuración del almacén Redux permanece igual que antes. Lo único que necesitamos agregar es un punto de extremo para mutaciones y un componente que maneje el envío del formulario.
Paso 1: Crear un punto de extremo para mutaciones
Abra el archivo del servicio API:
src/services/api.js
Luego agregue la nueva definición de punto de extremo dentro del objeto 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;
Analicemos esta línea por línea.
Comprensión de builder.mutation()
addUser: builder.mutation({
Mientras que builder.query() está diseñado para obtener datos, builder.mutation() es el que se utiliza cuando se necesita modificar algo en el servidor.
Ejemplos comunes de su uso:
- Crear usuarios
- Registrar cuentas
- Conectarse
- Actualizar productos
- Borrar publicaciones
Cada vez que tu aplicación escribe o modifica datos en el backend, una mutación es la herramienta adecuada.
Comprensión de query()
query: (newUser) => ({
Esta función recibe los datos que le pasas desde tu código de React.
Por ejemplo, si envías:
addUser({
name: "John",
email: "john@example.com",
});
entonces el parámetro llamado
newUser
contendrá:
{
name: "John",
email: "john@example.com"
}
Ese objeto es el que se envía como cuerpo de la solicitud.
Comprensión de la URL
url: "users",
Dado que la URL base está configurada como:
https://jsonplaceholder.typicode.com/
RTK Query las combina automáticamente en:
https://jsonplaceholder.typicode.com/users
así que nunca tienes que escribir la dirección completa por tu cuenta.
Comprensión del método
method: "POST",
Esta línea indica explícitamente a RTK Query que envíe una solicitud POST. Si no se incluye, la solicitud usa GET por defecto.
Comprensión del cuerpo
body: newUser,
Lo que quiera que esté almacenado en newUser se envía como carga de la solicitud, por ejemplo:
{
"name": "John",
"email": "john@example.com"
}
El servidor recibe ese objeto tal como fue creado.
Paso 2: Exportar el gancho generado
export const {
useAddUserMutation,
} = api;
Al igual que las consultas te proporcionan un gancho generado automáticamente como
useGetUsersQuery()
las mutaciones generan su propio gancho de forma automática:
useAddUserMutation()
Nunca escribes este gancho a mano: RTK Query lo construye por ti en función del nombre del endpoint.
Paso 3: Crear el componente React
Crea un archivo nuevo:
src/components/AddUser.jsx
y agrega este código:
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;
Analicemos qué está sucediendo aquí.
Comprensión de useAddUserMutation()
const [
addUser,
{
isLoading,
isSuccess,
error,
},
] = useAddUserMutation();
A diferencia de los ganchos de consulta, los ganchos de mutación devuelven un array en lugar de un objeto. El primer elemento:
addUser
Es la función que se llama para activar la solicitud, mientras que el segundo elemento es un objeto que contiene detalles útiles sobre el estado de dicha solicitud.
Comprensión de addUser()
await addUser({
name,
email,
});
Llamar a esta función envía una solicitud de la siguiente manera:
POST /users
que lleva un payload en formato JSON como este:
{
"name": "John",
"email": "john@example.com"
}
En el backend, ese payload se utiliza para crear un registro de usuario completamente nuevo.
Comprensión de los estados de mutación
Junto con la función desencadenante, RTK Query proporciona varios indicadores de estado que describen lo que está sucediendo con la solicitud.
isLoading
isLoading
Este indicador pasa a true mientras la mutación está en proceso, lo que lo hace ideal para desactivar un botón de envío o mostrar un spinner hasta que llegue la respuesta.
isSuccess
isSuccess
Una vez que la solicitud se completa sin errores, este valor pasa a ser true, lo que le brinda una señal clara para mostrar un mensaje de confirmación o redirigir al usuario a otra ubicación.
error
error
Si el servidor responde con un fallo, los detalles se muestran aquí, permitiéndole mostrar un error legible en lugar de una interfaz dañada.
Paso 4 — Renderizar el componente
Abra el archivo principal de la aplicación:
src/App.jsx
y reemplace su contenido por el siguiente:
import AddUser from "./components/AddUser";
function App() {
return <AddUser />;
}export default App;
Luego inicie el servidor de desarrollo:
npm run dev
Rellene los campos del formulario y haga clic en Agregar usuario — RTK Query se encargará de enviar la solicitud POST por usted.
Flujo completo de la solicitud
A continuación, un resumen de lo que ocurre en el fondo, desde el envío del formulario hasta la actualización del estado:
User Fills Form
│
▼
Clicks Submit
│
▼
addUser()
│
▼
Generated Mutation Hook
│
▼
RTK Query
│
▼
fetchBaseQuery()
│
▼
POST Request
│
▼
Server Response
│
▼
Mutation State Updates
│
▼
React Re-renders
Fíjese en todo lo que falta en este flujo:
fetch()axios.post()useEffect()- Estatus de carga controlado manualmente
- Estatus de error controlado manualmente
RTK Query se encarga de todo esto en segundo plano.
builder.query() vs builder.mutation()
Saber cuándo utilizar cada uno de estos métodos del constructor es muy importante.
builder.query() está diseñado para obtener datos, generalmente a través de solicitudes GET, y genera hooks como useGetUsersQuery() que se ejecutan automáticamente tan pronto como se renderiza el componente. Por el contrario, builder.mutation() está destinado a modificar datos mediante métodos como POST, PUT, PATCH o DELETE. Produce hooks como useAddUserMutation() que solo se ejecutan cuando se llama explícitamente a la función desencadenante, en lugar de al renderizarse. En resumen, las consultas sirven para leer y las mutaciones para crear, actualizar o eliminar.
Elegir la herramienta adecuada para cada tarea mantiene la lógica de tu API coherente y fácil de comprender.
Mejores prácticas
Ten en cuenta estas pautas cada vez que construyas funcionalidades POST con RTK Query:
- Utiliza
builder.mutation()siempre que una operación modifique datos en el servidor.
isLoading, isSuccess y error para que la interfaz sea receptiva e informativa.addUser, createPost o registerUser.unwrap() si prefiere manejar los casos de éxito y error con un bloque try...catch dentro de sus componentes.Puntos clave
Al seguir esta guía, ha aprendido cómo:
- Configurar una mutación con
builder.mutation(). - Conectar un punto de extremo POST dentro de una API slice.
- Enviar datos JSON a un servicio backend.
- Utilice el gancho autogenerado
useAddUserMutation(). - Envíe una solicitud POST directamente desde un formulario de React.
- Gestione los estados de carga, éxito y error sin código genérico manual.
- Diferencie las consultas de las mutaciones.
- Aplique prácticas sólidas para crear interacciones con APIs mantenibles.
Este mismo patrón aparece constantemente en aplicaciones en producción: flujos de registro de usuarios, autenticación, publicación de artículos de blog, realización de pedidos y numerosos otros escenarios de creación de datos.
¿Qué sigue?
Una vez que domine las solicitudes POST, el siguiente paso lógico es aprender a actualizar y eliminar registros existentes.
La guía que viene a continuación abordará:
- Actualización de registros con solicitudes PUT y PATCH.
- Eliminación de registros mediante solicitudes DELETE.
- Transmitir IDs dinámicos a los puntos finales de mutación.
- Invalidar los datos en caché para que la interfaz de usuario se actualice automáticamente.
- Utilizar etiquetas —
providesTagsyinvalidatesTags— para mantener todo sincronizado sin necesidad de volver a cargar manualmente.
Para cuando termines esa guía, estarás preparado para crear una aplicación completa CRUD utilizando patrones RTK Query listos para producción.
Lecturas relacionadas
- Los cambios en los valores predeterminados de TypeScript 6.0: Una guía práctica de migración — Aprende cuáles son los nueve valores predeterminados del compilador de TypeScript 6.0 que han cambiado, cómo configurar tsconfig para el año 2026 y cómo preparar bases de código para TypeScript 7 basado en Go.
- Los estándares de JavaScript full-stack en 2026: TypeScript, RSC y más — Explica por qué TypeScript, React Server Components y un enfoque de gestión de estado más eficiente se han convertido en la pila estándar para equipos que trabajan con JavaScript en 2026.