RTK Query
Los datos cuyo origen autoritativo es el backend son server state. RTK Query es la recomendación por defecto del equipo Redux para fetching y caché en una app Redux: deduplica peticiones, guarda el resultado, expone loading/error y genera hooks.
No sustituye toda la lógica async (capítulos 4 y 7). Sí sustituye el patrón fetch → thunk → loading → caché manual para CRUD HTTP habitual.
Documentación: RTK Query overview, Queries, Mutations, createApi.
createApi + fetchBaseQuery
Con React, importa desde @reduxjs/toolkit/query/react para obtener los hooks.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
tagTypes: ['Tareas'],
endpoints: (build) => ({
getTareas: build.query({
query: () => 'tareas',
providesTags: ['Tareas'],
}),
addTarea: build.mutation({
query: (body) => ({ url: 'tareas', method: 'POST', body }),
invalidatesTags: ['Tareas'],
}),
}),
})
export const { useGetTareasQuery, useAddTareaMutation } = apifetchBaseQuery envuelve fetch. Un baseUrl por API; varios createApi si hay orígenes distintos.
Store
Hay que registrar reducer y middleware. Sin el middleware no hay caché ni invalidación.
import { configureStore } from '@reduxjs/toolkit'
import { api } from './api'
import tareasReducer from './tareasSlice'
export const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
tareas: tareasReducer, // UI cliente: filtro, selección
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(api.middleware),
})tareasSlice aquí es estado cliente (filtro), no una segunda copia de /tareas.
Hooks: data, loading, error
function Tablero() {
const { data, error, isLoading } = useGetTareasQuery()
const [addTarea, { isLoading: guardando }] = useAddTareaMutation()
if (isLoading) return <p>Cargando…</p>
if (error) return <p>No se pudieron cargar las tareas</p>
return (
<ul>
{data.map((t) => (
<li key={t.id}>{t.titulo}</li>
))}
</ul>
)
}isLoading es la primera carga sin dato; isFetching incluye refetch con dato previo. La mutación invalida la etiqueta Tareas y Query vuelve a pedir getTareas (o marca el cache stale, según config).
setupListeners(store.dispatch) habilita refetchOnFocus / refetchOnReconnect si los activas en el endpoint o en createApi.
Errores habituales
- Olvidar
api.middlewarey preguntarse por qué no refetch-ea. - Copiar
dataal slice de entidades “para normalizarlo” sin necesidad (Query ya es la caché). - Un
createApigigante con 40 endpoints no relacionados; parte por base URL / bounded context.
Buenas prácticas
- Tags (
providesTags/invalidatesTags) en lugar derefetch()por todas partes. - Estado cliente (filtro, item seleccionado) fuera de
api. - Auth:
prepareHeadersenfetchBaseQueryleyendo el token delgetState(), no hardcodeado.
Ejercicio
- Monta
getTareas+addTareay comprueba en DevTools las actionsapi/.... - Quita
invalidatesTagsy observa que la lista no se actualiza tras el POST. - Añade un
filtroen el slice de UI y filtradataen el componente o un selector.
Siguiente paso
Continúa con Middleware.
