Reductores adicionales en Redux
Abramos nuestra aplicación de productos,
y en ella el archivo productsSlice.js. Probablemente
habrás notado que creamos el thunk fetchProducts
como una función separada? Lo hicimos así, porque
createSlice no admite la definición
de thunks. ¿Cómo podemos en este caso hacer que
el reductor del slice products responda a las acciones,
que están definidas fuera de products?
Después de todo, necesitamos procesar las acciones
que envía el thunk fetchProducts.
Para tales casos, createSlice tiene
la propiedad extraReducers, que permite
añadir reductores adicionales, que
a su vez procesarán las acciones,
definidas no en este slice.
Ahora, en el cuerpo de la función createSlice
después de la propiedad reducers con todos los reductores
añadamos otro método extraReducers:
extraReducers() {},
A este método debemos pasar un objeto
builder, que tiene métodos, con
la ayuda de los cuales se pueden añadir
reductores adicionales:
extraReducers(builder) {},
Usaremos uno de los métodos de builder -
addCase, que toma como primer parámetro
un action creator, y como segundo un reducer. Una de
las acciones que nos enviará
fetchProducts al hacer la solicitud es
fetchProducts.pending, que nos indica
que la solicitud ha sido enviada. En este
caso, cambiemos el estado a 'in progress'
(antes era 'idle'):
extraReducers(builder) {
builder.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
},
Ahora procesemos la acción que se enviará
en caso de una solicitud exitosa. Aquí cambiaremos
no solo el estado en el store a
'success', sino que también tomaremos los productos en
el slice products desde el payload de la acción.
Para recoger todos los productos necesitaremos
el método concat:
extraReducers(builder) {
builder
.addCase(fetchProducts.pending, (state) => {
state.status = 'in progress'
})
.addCase(fetchProducts.fulfilled, (state, action) => {
state.status = 'success'
state.products = state.products.concat(action.payload)
})
},
En caso de una solicitud fallida, cambiaremos
el estado a 'fail' y guardaremos en el store
el mensaje de error:
.addCase(fetchProducts.rejected, (state, action) => {
state.status = 'fail'
state.error = action.error.message
})
Si ahora ejecutamos nuestra aplicación
y en el menú hacemos clic en 'Products',
después de un par de segundos (¿recuerdas el retraso
que establecimos en el servidor?) veremos
la lista de productos.
De la misma manera veremos los cambios en Redux
DevTools. Ahora nuestros productos aparecerán
en el store (mira la pestaña 'State'),
si hiciste clic en la acción
products/fetchProducts/fulfilled.
Allí también aparecerá el nuevo estado 'success'.
Haz clic ahora en la acción
products/fetchProducts/pending y mira
en qué se diferencia ahora la pestaña 'State'.
El único momento desagradable que
puede ocurrirte (hablé de esto
en la lección anterior) es la duplicación de
la solicitud de datos. Como resultado, en nuestra
lista obtendremos no 8, sino la friolera de
16 productos y advertencias críticas
en la consola del desarrollador. Vamos a
tratar esto en la siguiente lección.
Abre tu aplicación de estudiantes.
Abre en ella el archivo studentsSlice.js. En
el cuerpo de la función createSlice después de la propiedad
reducers añade la propiedad extraReducers.
Pasa al método extraReducers el builder.
Con el método builder.addCase
añade el procesamiento para las acciones pending,
fulfilled y rejected, que
envía fetchStudents al solicitar
datos, como se muestra en la lección.