Asincronismo en Redux Toolkit: CreateAsyncThunk y UI Slice

Clase 21 de 22Curso Profesional de React.js y Redux

Contenido del curso

Resumen

Manejar operaciones asíncronas en Redux solía requerir configuraciones adicionales como Redux Thunk, pero Redux Toolkit simplifica este proceso con un método integrado llamado createAsyncThunk. A continuación se explica paso a paso cómo implementar llamadas asíncronas y cómo crear un slice de UI para controlar el estado de carga, todo con menos código y mayor claridad.

¿Cómo funciona createAsyncThunk para llamadas asíncronas?

El método createAsyncThunk se importa directamente desde Redux Toolkit y reemplaza la necesidad de instalar Redux Thunk como dependencia separada [01:00]. Este método recibe dos parámetros principales:

  • Nombre de la acción: sigue la convención nombreDelSlice/nombreDelType, por ejemplo data/fetchPokémonsWithDetails.
  • Payload creator: es el callback asíncrono que se ejecuta al disparar la acción.

Dentro del payload creator, la función recibe dos argumentos [02:05]. El primero corresponde a los parámetros que enviamos al despachar la acción; si no se necesitan, se usa un guion bajo (_) por convención. El segundo es el thunkAPI, un objeto con múltiples propiedades entre las que destaca dispatch, que permite despachar otras acciones dentro del mismo thunk.

javascript import { createAsyncThunk } from '@reduxjs/toolkit'; import { getPokémons, getPokémonWithDetails } from '../api';

export const fetchPokémonsWithDetails = createAsyncThunk( 'data/fetchPokémonsWithDetails', async (_, { dispatch }) => { dispatch(setLoading(true)); const pokémonList = await getPokémons(); const pokémonsDetail = await Promise.all( pokémonList.map((p) => getPokémonWithDetails(p)) ); dispatch(setPokémons(pokémonsDetail)); dispatch(setLoading(false)); } );

Al centralizar toda la lógica asíncrona en el thunk, el loader se sincroniza correctamente con la obtención de datos. Antes, al tener disparadores separados, el loader se ocultaba antes de que la lista estuviera lista [03:22].

¿Qué son los sufijos pending y fulfilled?

Cuando se utiliza createAsyncThunk, Redux Toolkit genera automáticamente acciones con sufijos como pending, fulfilled y rejected [08:15]. Estos estados se pueden escuchar mediante la propiedad extraReducers al crear un slice, usando un builder que permite ejecutar lógica adicional dependiendo de si la promesa está pendiente, se completó o falló.

¿Cómo crear el UI slice para manejar el estado de carga?

El slice de UI se encarga de gestionar propiedades visuales como el loading [10:10]. Su creación sigue el mismo patrón que cualquier otro slice:

javascript import { createSlice } from '@reduxjs/toolkit';

const initialState = { loading: false, };

const uiSlice = createSlice({ name: 'ui', initialState, reducers: { setLoading: (state, action) => { state.loading = action.payload; }, }, });

export const { setLoading } = uiSlice.actions; export default uiSlice.reducer;

Gracias a que Redux Toolkit usa Immer.js internamente, es posible modificar el estado directamente con state.loading = action.payload sin romper la inmutabilidad [11:02]. No hay necesidad de retornar un nuevo objeto.

¿Cómo integrar el nuevo slice en el store?

Una vez creado, el reducer del UI slice se agrega al rootReducer combinado [11:45]:

javascript import uiReducer from './slices/uiSlice';

const rootReducer = combineReducers({ data: dataReducer, ui: uiReducer, });

En el componente principal, el selector de loading accede al estado con state.ui.loading, eliminando métodos como .get() o .toJS() que se usaban con la librería Immutable [07:30]. El shallowEqual se mantiene porque su función es evitar re-renderings innecesarios y no depende de Immutable.

¿Cómo limpiar el proyecto después de migrar a Redux Toolkit?

Una buena práctica al finalizar la migración es eliminar archivos y dependencias obsoletas [14:00]:

  • Borrar los archivos de action types y action creators anteriores.
  • Eliminar los reducers específicos que fueron reemplazados por los slices, conservando solo el rootReducer.
  • Desinstalar las librerías immutable y redux-immutable del package.json, ya que Redux Toolkit maneja la inmutabilidad con Immer.js de forma nativa.

Esto se puede hacer ejecutando npm uninstall immutable redux-immutable o eliminando las entradas del package.json y ejecutando npm install nuevamente.

Con estos cambios, el proyecto queda más limpio y con significativamente menos código que la implementación tradicional. Redux Toolkit ofrece funcionalidades avanzadas más allá de lo cubierto aquí, como createEntityAdapter o RTK Query, que vale la pena explorar en la documentación oficial cuando los proyectos crecen en complejidad.