Redux Thunk para acciones asíncronas

Resumen

Cuando trabajas con Redux puro, los action creators solo permiten flujos síncronos. Pero si necesitas llamar a una API antes de despachar una acción, necesitas un middleware como Redux Thunk, que te permite escribir lógica asíncrona y separar responsabilidades entre componentes y actions.

Qué es Redux Thunk y por qué usarlo

Redux por defecto solo despacha objetos planos de forma síncrona. Aquí es donde entra Thunk como enhancer del store.

Thunk es un concepto de programación donde una función se usa para retrasar la evaluación, el cálculo o la ejecución de una operación. Aplicado a Redux, te permite escribir action creators que en lugar de retornar un objeto, retornan otra función. Esa función recibe el dispatch y decide cuándo y cómo enviar la acción al reducer [01:05].

¿Para qué sirve Redux Thunk? Sirve para despachar acciones asíncronas, retrasar el dispatch hasta que se cumpla una condición y separar la lógica de peticiones HTTP del componente.

Esto es útil, por ejemplo, cuando necesitas obtener los detalles de cada Pokémon desde una API antes de actualizar el estado global.

Cómo crear un action creator asíncrono con Thunk

Primero instala la dependencia con npm install redux-thunk. Luego, dentro de tu carpeta actions, crea un nuevo action creator que retorne una función en lugar de un objeto [02:10].

La estructura básica se ve así:

javascript import { setPokemons } from './index';

export const getPokemonsWithDetails = (pokemons = []) => async (dispatch) => { const pokemonsDetailed = await Promise.all( pokemons.map(pokemon => getPokemonDetail(pokemon)) ); dispatch(setPokemons(pokemonsDetailed)); };

Fíjate en tres detalles importantes:

  • La función externa recibe los pokemons como parámetro y por defecto es un arreglo vacío.
  • La función interna recibe el dispatch, equivalente al next de un middleware personalizado.
  • Dentro usas await para resolver las llamadas a la API, por eso la función debe ser async.

Por qué mover la lógica fuera del componente

Dejar las peticiones dentro del componente mezcla responsabilidades. Tu App.js debería preocuparse por renderizar, no por orquestar llamadas a APIs.

Al mover esa lógica al action creator, el componente queda más limpio: solo despacha getPokemonsWithDetails(pokemons) y olvida cómo se resuelven los detalles. El código se vuelve más legible y testeable.

Cómo integrar Thunk como middleware en el store

La segunda parte es registrar Thunk en la configuración del store. En tu archivo index.js importa el middleware y agrégalo antes de logger [04:30].

javascript import thunk from 'redux-thunk'; import { createStore, applyMiddleware, compose } from 'redux';

const composeAlternative = window.REDUX_DEVTOOLS_EXTENSION_COMPOSE || compose;

const store = createStore( reducer, composeAlternative(applyMiddleware(thunk, logger)) );

El composeAlternative resuelve un conflicto común: la extensión Redux DevTools instalada de forma simple compite con Thunk. Para que ambos convivan, usas el compose que inyecta la extensión cuando existe el objeto window, y si no, vuelves al compose por defecto de Redux.

¿Qué hace __REDUX_DEVTOOLS_EXTENSION_COMPOSE__? Es una función que inyecta la extensión Redux DevTools en el navegador para combinar middlewares y mantener visibles las acciones en el panel de depuración.

Verificar que todo funcione

Tras guardar los cambios e inicializar el servidor, la aplicación debería comportarse igual que antes, pero con responsabilidades mejor distribuidas. En Redux DevTools verás tus acciones despachadas y el estado con la lista completa de Pokémon.

Qué habilidades y conceptos te llevas de esta clase

Más allá del código, hay varias ideas que vale la pena fijar:

  • Middleware como enhancer del store: Thunk amplía las capacidades nativas de Redux para manejar asincronía [00:35].
  • Action creators que retornan funciones: el patrón clave que diferencia un thunk de una acción normal [01:50].
  • Separación de responsabilidades: mover la lógica de API del componente al action creator mejora la mantenibilidad [02:00].
  • Composición de middlewares con DevTools: el truco del composeAlternative evita conflictos entre Thunk y la extensión del navegador [05:15].
  • Async/await dentro de Redux: ahora puedes usar Promise.all y await sin romper el flujo de Redux.

Thunk no es la única vía para manejar asincronía en Redux. Otra alternativa muy usada es Redux Saga, que aborda el mismo problema con generadores y un modelo distinto. ¿Has probado alguna de las dos? Cuéntame en los comentarios cuál prefieres y por qué.