Contenido del curso
Introducción a nuestro proyecto
¡Atraparlos ya!
React.js + Redux
Middlewares
Avanzando la ui
Inmutabilidad
Avanzado
Despedida del curso
createAsyncThunk para peticiones asíncronas
Resumen
Manejar peticiones asíncronas en Redux solía requerir Redux Thunk, configuración manual y bastante código repetitivo. Con createAsyncThunk de Redux Toolkit puedes centralizar el fetch, el loader y el dispatch en un solo lugar, y este recorrido te muestra cómo hacerlo paso a paso junto con la creación de un UI slice para controlar estados de carga.
¿Qué es createAsyncThunk y por qué reemplaza a Redux Thunk?
Es un método que crea acciones asíncronas integradas al ciclo de vida de Redux Toolkit, así que ya no necesitas instalar Redux Thunk por separado.
¿Qué hace createAsyncThunk? Genera una acción asíncrona que dispara automáticamente tres estados: pending, fulfilled y rejected. Tú solo escribes la lógica del fetch y Redux Toolkit se encarga del resto.
Para declararlo, importa el método desde Redux Toolkit y exporta una constante con el thunk [00:30]. Recibe dos parámetros clave:
- El nombre de la acción, siguiendo la convención
nombreSlice/nombreType, por ejemplodata/fetchPokemonWithDetails. - El payload creator, que es el callback asíncrono que se ejecuta al disparar la acción.
El payload creator recibe a su vez dos argumentos: los parámetros que envías al llamar la acción (un id, por ejemplo) y el thunkAPI, del cual desestructuramos el dispatch para disparar otras acciones desde dentro [01:30].
¿Cómo se estructura el thunk para traer los pokémon con detalles?
Dentro del callback asíncrono delegamos toda la responsabilidad: disparar el loader, hacer el fetch y volver a disparar el loader al terminar. Así evitas el bug clásico donde el loader se oculta antes de que la lista aparezca, porque ambos disparadores conviven en el mismo flujo [02:20].
El flujo queda así:
dispatch(setLoading(true))al inicio.- Llamada a la API con
getPokemonsy luego unPromise.allque mapea cada pokémon agetPokemonWithDetails. dispatch(setPokemons(pokemonsDetail))con la lista ya enriquecida.dispatch(setLoading(false))al final.
¿Cómo crear un UI slice para manejar el loading?
El UI slice centraliza estados visuales transversales como el loader, modales o notificaciones. Mantenerlo separado del slice de datos respeta el principio de responsabilidad única.
En slices/ui.slice.js importas createSlice y defines tres piezas:
- name:
'ui'. - initialState:
{ loading: false }. - reducers: un
setLoadingque recibestateyaction, y asignastate.loading = action.payload[06:45].
Luego exportas el action creator (export const { setLoading } = uiSlice.actions) y el reducer por defecto (export default uiSlice.reducer). Finalmente registras el reducer dentro del root reducer combinado bajo la llave ui.
¿Por qué puedo mutar el estado dentro del reducer? Redux Toolkit usa Immer internamente, así que escribes código que parece mutable pero produce un estado inmutable de forma segura.
¿Dónde se dispara setLoading dentro del thunk?
Una vez creado el slice, vuelves al dataSlice e importas setLoading. Lo invocas con true antes del fetch y con false después de despachar setPokemons. De este modo el componente se mantiene limpio: solo dispara fetchPokemonWithDetails y olvida toda la coreografía interna [07:50].
En App.js la función fetchPokemon deja de ser asíncrona porque su único trabajo es dispatch(fetchPokemonWithDetails()). También sustituyes los selectores que usaban get de Immutable por accesos directos: state.data.pokemons y state.ui.loading. El shallowEqual se conserva porque sirve para evitar re-renderings y no está atado a Immutable.
¿Qué son los extraReducers y los sufijos pending y fulfilled?
Al abrir Redux DevTools verás acciones que tú no escribiste, como data/fetchPokemonWithDetails/pending y data/fetchPokemonWithDetails/fulfilled. Son los estados que createAsyncThunk emite automáticamente.
Para reaccionar a ellos, Redux Toolkit ofrece la propiedad extraReducers dentro de createSlice, donde puedes escuchar el ciclo de vida del thunk con un builder:
pending: la promesa arrancó.fulfilled: la promesa resolvió con éxito.rejected: la promesa falló.
Ahí puedes mover el control del loader o manejar errores sin ensuciar el callback principal [09:40].
¿Cómo limpiar el proyecto al migrar a Redux Toolkit?
Una buena práctica al refactorizar es eliminar lo que ya no usas. En este caso desaparecen:
- La carpeta
actionscon sus actionTypes y actionCreators. - Los reducers individuales viejos de
pokemonsyui(sin borrar el root reducer). - Las dependencias
immutableyredux-immutabledelpackage.json, ya que Redux Toolkit trae Immer por defecto.
Para desinstalarlas usa npm uninstall immutable redux-immutable o edita el package.json y vuelve a correr npm install [13:10].
¿Y los componentes que disparaban acciones viejas?
En PokemonCard el dispatch apuntaba al action creator antiguo. Cambias el import para que apunte al slice (setFavorite exportado desde dataSlice.actions) y el botón de favoritos vuelve a funcionar sin tocar más lógica.
Con esto tienes una base sólida para escalar: thunks asíncronos limpios, un UI slice reutilizable y un proyecto sin librerías muertas. ¿Qué otro estado global moverías a su propio slice en tu proyecto?