<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Manuel L. Camarena</title>
    <description>The latest articles on DEV Community by Manuel L. Camarena (@mlcamarena).</description>
    <link>https://dev.to/mlcamarena</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3301257%2Fb316e986-bf38-4291-a57b-02ac375cbd7f.png</url>
      <title>DEV Community: Manuel L. Camarena</title>
      <link>https://dev.to/mlcamarena</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mlcamarena"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Manuel L. Camarena</dc:creator>
      <pubDate>Sun, 29 Jun 2025 20:58:07 +0000</pubDate>
      <link>https://dev.to/mlcamarena/-1d50</link>
      <guid>https://dev.to/mlcamarena/-1d50</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj" class="crayons-story__hidden-navigation-link"&gt;Guía en español para configurar Redux y Redux Sagas con Typescript sin volverse loco.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mlcamarena" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3301257%2Fb316e986-bf38-4291-a57b-02ac375cbd7f.png" alt="mlcamarena profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mlcamarena" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Manuel L. Camarena
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Manuel L. Camarena
                
              
              &lt;div id="story-author-preview-content-2636190" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mlcamarena" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3301257%2Fb316e986-bf38-4291-a57b-02ac375cbd7f.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Manuel L. Camarena&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 29 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj" id="article-link-2636190"&gt;
          Guía en español para configurar Redux y Redux Sagas con Typescript sin volverse loco.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/redux"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;redux&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/reduxsaga"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;reduxsaga&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            17 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>react</category>
      <category>redux</category>
      <category>reduxsaga</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Guía en español para configurar Redux y Redux Sagas con Typescript sin volverse loco.</title>
      <dc:creator>Manuel L. Camarena</dc:creator>
      <pubDate>Sun, 29 Jun 2025 15:02:27 +0000</pubDate>
      <link>https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj</link>
      <guid>https://dev.to/mlcamarena/guia-en-espanol-para-configurar-redux-y-redux-sagas-con-typescript-sin-volverse-loco-3nlj</guid>
      <description>&lt;p&gt;Si estás leyendo esto, probablemente eres desarrollador frontend, y usas o estás aprendiendo &lt;strong&gt;React&lt;/strong&gt;. Dado el caso, seguro que has visto &lt;strong&gt;Redux&lt;/strong&gt; nombrado muchas veces en ofertas de empleo, blogs de tecnología etc. Estamos hablando de una de las librerías más usadas y potentes en la gestión de estado en el frontend en la actualidad. Está disponible como &lt;strong&gt;Redux&lt;/strong&gt; tal cual para &lt;strong&gt;React&lt;/strong&gt;, tenemos &lt;strong&gt;Ngrx&lt;/strong&gt; para &lt;strong&gt;Angular&lt;/strong&gt; y &lt;strong&gt;Vuex&lt;/strong&gt; o &lt;strong&gt;Pinia&lt;/strong&gt; para &lt;strong&gt;Vue&lt;/strong&gt;. Si no tienes conocimientos básicos de &lt;strong&gt;React&lt;/strong&gt; y de conceptos como &lt;strong&gt;Provider&lt;/strong&gt;, &lt;strong&gt;Hook&lt;/strong&gt; y demás, esta guía no es aún para ti.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducción teórica.
&lt;/h2&gt;

&lt;p&gt;Antes de entrar en materia práctica, tenemos que conocer una serie de conceptos cuyo entendimiento nos hará más sencilla la implementación. En primer lugar, debemos conocer que &lt;strong&gt;Redux&lt;/strong&gt; en sí es una librería de &lt;strong&gt;Javascript&lt;/strong&gt; basada en el patrón &lt;strong&gt;Flux&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El patrón &lt;strong&gt;Flux&lt;/strong&gt; es un patrón de arquitectura del frontend desarrollado por &lt;strong&gt;Facebook&lt;/strong&gt; para gestionar el flujo de los datos en las aplicaciones web, con la intención de hacerlo predecible y fácil de debuggear. Se busca crear un flujo unidireccional de datos siguiendo los componentes básicos de este patrón.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;: Objetos que definen qué ocurre.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dispatcher&lt;/strong&gt;: Distribuidores que envían las acciones a los stores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;: Esquema de datos que contiene el estado de la aplicación y la lógica de negocio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Views&lt;/strong&gt;: Componentes de la interfaz de usuario.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El flujo marca el siguiente recorrido: &lt;code&gt;Action → Dispatcher → Store → View → Action&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Muchas librerías como &lt;strong&gt;Zustand&lt;/strong&gt; y demás tienen su origen en este patrón también, &lt;strong&gt;Redux&lt;/strong&gt; es simplemente una implementación de este patrón con características propias. Por ejemplo, en &lt;strong&gt;Redux&lt;/strong&gt; sólo existe una única &lt;code&gt;store&lt;/code&gt;, donde estarán, en forma de árbol, todos los datos del estado de nuestra aplicación. Este estado de la aplicación es un objeto inmutable, de sólo lectura, únicamente pueden cambiar sus propiedades (teoría básica de referencias de objetos de &lt;strong&gt;Javascript&lt;/strong&gt; y &lt;strong&gt;Typescript&lt;/strong&gt;) mediante la emisión de acciones.&lt;/p&gt;

&lt;p&gt;Tres conceptos importantes propios de &lt;strong&gt;Redux&lt;/strong&gt; (dos de &lt;strong&gt;Redux&lt;/strong&gt; en sí y otro del kit de &lt;strong&gt;Redux Toolkit&lt;/strong&gt;) son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reducers&lt;/strong&gt;: Son funciones que reciben el estado actual y una acción concreta lanzada, determinando así los cambios que este estado va a sufrir y devolviendo su nueva versión.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slice&lt;/strong&gt; (&lt;strong&gt;Redux toolkit&lt;/strong&gt;): Representa una porción del estado en sí, uno de esos fragmentos del árbol, junto con los &lt;code&gt;reducers&lt;/code&gt; y los &lt;code&gt;actions&lt;/code&gt; que lo manejan, todo agrupado en único fichero y entidad propia.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middleware&lt;/strong&gt;: Función que se ejecuta entre el momento que se dispara un &lt;code&gt;action&lt;/code&gt; y el momento en que llega al &lt;code&gt;reducer&lt;/code&gt;. Podríamos decir que es algo así como un interceptor. Su función principal es la gestión de efectos secundarios. Este es el concepto más importante para entender qué es &lt;strong&gt;Redux Saga&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redux&lt;/strong&gt; así tal cual es de por si una herramienta muy potente para la gestión del estado como hemos dicho, pero usando los &lt;code&gt;middleware&lt;/code&gt; adecuados, como &lt;strong&gt;Redux Saga&lt;/strong&gt;, podemos llevar nuestra aplicación a otro nivel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux Saga&lt;/strong&gt; es un &lt;code&gt;middleware&lt;/code&gt; especializado que usa funciones generadoras (funciones que pueden pausarse y reanudarse) de &lt;strong&gt;Javascript&lt;/strong&gt; para manejar los efectos secundarios de manera muy potente y declarativa. Ejemplos de uso son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cancelar tareas en progreso.&lt;/li&gt;
&lt;li&gt;Ejecutar múltiples tareas en paralelo.&lt;/li&gt;
&lt;li&gt;Manejar las requests de nuestra aplicación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;También es necesario conocer que es &lt;code&gt;yield&lt;/code&gt;, algo así como un botón de pausa, que espera a que la sentencia a la que precede termine, haga algo. Algo similar al &lt;code&gt;await&lt;/code&gt;, que se usa en estas funciones generadoras.&lt;/p&gt;

&lt;p&gt;Hasta aquí, la explicación teórica. Es bastante probable que hasta ahora, todo te suene un poco a chino si no estás habituado al uso de este tipo de librerías, o incluso aunque sepas los conceptos, toda la arquitectura del patrón &lt;strong&gt;Redux&lt;/strong&gt; es un poco difícil de digerir hasta que no tienes bastante práctica con ello, la curva de aprendizaje de esta librería puede ser bastante elevada incluso para gente muy senior, así que vayamos paso a paso a la explicación más práctica.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalación.
&lt;/h2&gt;

&lt;p&gt;Vamos a partir de la base de que tienes ya tu aplicación de &lt;strong&gt;React&lt;/strong&gt; inicializada, tu entorno de &lt;strong&gt;node&lt;/strong&gt; y &lt;strong&gt;npm&lt;/strong&gt; bien preparado. Si no es el caso, vas a necesitar acudir a una guía de &lt;strong&gt;React&lt;/strong&gt; y aprender conceptos más básicos antes de llegar a necesitar este post.&lt;/p&gt;

&lt;p&gt;El comando con los paquetes que necesitaremos instalar son:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react-redux redux-saga @reduxjs/toolkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con estos paquetes, tendremos la base de &lt;strong&gt;Redux&lt;/strong&gt; en &lt;strong&gt;React&lt;/strong&gt; con &lt;code&gt;react-redux&lt;/code&gt;, las herramientas de &lt;strong&gt;Redux Toolkit&lt;/strong&gt; para facilitar la instalación, y el middleware &lt;strong&gt;Redux Saga&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura de directorios recomendada.
&lt;/h2&gt;

&lt;p&gt;En este punto, antes de empezar, tengo que aclarar, que la estructura de directorios, tanto para este patrón de arquitectura como para cualquier aplicación, es algo totalmente abierto a gusto del usuario, sin olvidar por supuesto que existen ciertos estándares y convenciones que facilitan la lectura y el entendimiento de esta estructura para cualquier proyecto. Vamos a pensar que partimos de la estructura básica de tener dentro del source de nuestro proyecto, diferentes directorios por features, components, hooks etc. Lo que yo (y el estándar para estas librerías que estamos viendo, el cual sigo fielmente porque me parece lo más claro) recomiendo, sería tener un directorio &lt;code&gt;store&lt;/code&gt; con la siguiente estructura, pensando que tenemos por ejemplo una feature &lt;strong&gt;Book&lt;/strong&gt; para una sección de detalles de un libro:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2n1hocsipeiuhbg0v4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2n1hocsipeiuhbg0v4k.png" alt="Image description" width="318" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto sería la estructura más básica que necesitaríamos en algún proyecto, un directorio &lt;code&gt;sagas&lt;/code&gt;, &lt;code&gt;selectors&lt;/code&gt; y &lt;code&gt;slices&lt;/code&gt; dentro de &lt;code&gt;store&lt;/code&gt;. Dentro de estos, podemos tener más directorios por cada propia feature por ejemplo, o directamente ficheros si es una aplicación pequeñita, como el ejemplo. Por supuesto, un archivo &lt;code&gt;index&lt;/code&gt; donde crearemos y configuraremos el &lt;code&gt;store&lt;/code&gt; de nuestra aplicación. Todo esto lo veremos paso a paso en los siguientes puntos.&lt;/p&gt;

&lt;p&gt;Antes de pasar a ello, comentar que esta estructura es ampliable con más directorios, por ejemplo: &lt;code&gt;actions&lt;/code&gt;, para la creación de acciones que no modifiquen nuestro &lt;code&gt;store&lt;/code&gt; y no tengan cabida dentro de los &lt;code&gt;slices&lt;/code&gt;, acciones que sean únicamente interceptadas en las &lt;code&gt;sagas&lt;/code&gt; para cualquier función que se nos ocurra, o también, un directorio &lt;code&gt;middleware&lt;/code&gt; para hacer nuestras funciones interceptoras customizadas, pero esto es algo más avanzado que me gustaría ver en otro post en el futuro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurando un slice.
&lt;/h2&gt;

&lt;p&gt;Vamos a seguir con la idea de que tenemos una entidad &lt;strong&gt;Book&lt;/strong&gt; para el resto de la guía. Vamos a necesitar un &lt;code&gt;slice&lt;/code&gt; de nuestro estado dedicado a esta entidad (y a cada una de las necesarias en la aplicación).&lt;/p&gt;

&lt;p&gt;Para ello, creamos nuestro archivo correspondiente al &lt;code&gt;slice&lt;/code&gt; como vimos en el paso anterior. En primer lugar, será necesario definir el tipado correspondiente a este &lt;code&gt;slice&lt;/code&gt;. De inicios vamos a pensar que tendremos propiedades para saber el estado de loading, el estado de error, una lista de libros y un libro seleccionado. Y por supuesto, tenemos que definir un objeto de estado inicial en base a este tipado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk6ujk1s6bykxox5dmb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk6ujk1s6bykxox5dmb3.png" alt="Image description" width="602" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con el tipado y el &lt;code&gt;initialState&lt;/code&gt; ya definido, es momento de crear el &lt;code&gt;slice&lt;/code&gt;. Al crear el &lt;code&gt;slice&lt;/code&gt;, hemos de tener en cuenta que estamos creando tanto las &lt;code&gt;actions&lt;/code&gt; como los &lt;code&gt;reducers&lt;/code&gt; de esta sección del estado de una. La definición del tipado del estado de cada &lt;code&gt;slice&lt;/code&gt; es un punto crítico en esta arquitectura, se busca algo simple y entendible, generar caos dentro de los &lt;code&gt;slice&lt;/code&gt; incrementarán muchísimo la dificultad de escalado y mantenimiento de nuestra aplicación en futuro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux Toolkit&lt;/strong&gt; nos proporciona la función de &lt;code&gt;createSlice&lt;/code&gt;, que recibirá un objeto con las propiedades para definir el nombre de esta sección del estado, (será el prefijo de nuestras acciones, nos ayudará en la depuración de estas, sabiendo exactamente de qué &lt;code&gt;slice&lt;/code&gt; provienen), el estado inicial, los &lt;code&gt;reducers&lt;/code&gt;, y los &lt;code&gt;extra reducers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Definiremos la propiedad &lt;code&gt;reducers&lt;/code&gt; como un objeto cuyas claves serán nuestras &lt;code&gt;actions&lt;/code&gt;, y el valor, la función de los &lt;code&gt;reducers&lt;/code&gt; que se ejecutarán al lanzar cada &lt;code&gt;action&lt;/code&gt;. Esta función esperará dos parámetros, el estado, y la propia acción. Tiparemos esta acción con &lt;code&gt;PayloadAction&lt;/code&gt; también de &lt;strong&gt;Redux Toolkit&lt;/strong&gt;, con tipo genérico de lo que queramos que tenga esa &lt;code&gt;action&lt;/code&gt;, definiendo así a su vez los parámetros que necesitará esta &lt;code&gt;action&lt;/code&gt; para ser lanzada, y a los que tendremos acceso en el &lt;code&gt;reducer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La propiedad &lt;code&gt;extraReducers&lt;/code&gt; es un caso parecido, con ciertas peculiaridades: aquí no estamos definiendo acciones de este &lt;code&gt;slice&lt;/code&gt;, vamos a definir casos de acciones de otros &lt;code&gt;slices&lt;/code&gt; que podrán tener efecto en el estado de este. Sabiendo esto, se hace evidente una buena práctica más a la hora de definir los &lt;code&gt;slices&lt;/code&gt;, y es que, en el momento que tengamos alguna información que queramos guardar en el estado pero que no sean de la feature que estemos trabajando en ese momento, aunque sea relacionada, será mejor tenerla en otro &lt;code&gt;slice&lt;/code&gt; aparte, para no aumentar la complejidad de cada &lt;code&gt;slice&lt;/code&gt; innecesariamente y hacerlos propios de cada feature, pues con esas otras acciones de otros &lt;code&gt;slices&lt;/code&gt;, el nodo del estado que definimos aquí podrá verse también modificado.&lt;/p&gt;

&lt;p&gt;Esta propiedad espera una función que recibe como parámetro el &lt;code&gt;builder&lt;/code&gt; del &lt;code&gt;slice&lt;/code&gt;, teniendo la propiedad de &lt;code&gt;addCase&lt;/code&gt; que nos permitirá definir &lt;code&gt;reducers&lt;/code&gt; con estas acciones importadas de otro &lt;code&gt;slice&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Teniendo el &lt;code&gt;slice&lt;/code&gt; definido, exportaremos tanto sus acciones como sus &lt;code&gt;reducers&lt;/code&gt; con las propiedades correspondientes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyji2ie7q50oqsd0f0wgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyji2ie7q50oqsd0f0wgg.png" alt="Image description" width="800" height="928"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Definiendo la store.
&lt;/h2&gt;

&lt;p&gt;Y ahora, ¿qué hacemos con esto? Pues el siguiente paso y el crucial, es definir nuestra &lt;code&gt;store&lt;/code&gt; e inyectarla en nuestra aplicación, donde haremos uso de ella.&lt;/p&gt;

&lt;p&gt;Para ello, haremos uso del archivo &lt;code&gt;index&lt;/code&gt; dentro del directorio &lt;code&gt;store&lt;/code&gt; que creamos antes. Todo va siguiendo la lógica de la teoría que hemos visto. El conjunto de estos &lt;code&gt;reducers&lt;/code&gt; de los &lt;code&gt;slices&lt;/code&gt; es lo que forma nuestra &lt;code&gt;store&lt;/code&gt;, ¿verdad? Pues tenemos que combinarlos.&lt;/p&gt;

&lt;p&gt;Dentro de &lt;strong&gt;Redux Toolkit&lt;/strong&gt;, contamos con dos funciones esenciales, &lt;code&gt;combineReducers&lt;/code&gt; y &lt;code&gt;configureStore&lt;/code&gt;. Con &lt;code&gt;combineReducers&lt;/code&gt;, conseguiremos un &lt;code&gt;reducer&lt;/code&gt; combinado de todos los definidos en cada &lt;code&gt;slice&lt;/code&gt;, y una vez lo tengamos, hacemos uso del &lt;code&gt;configureStore&lt;/code&gt;, es una función que nos devolverá nuestra &lt;code&gt;store&lt;/code&gt; ya lista, recibe un objeto con múltiples propiedades, pero nosotros usaremos las esenciales para definir los &lt;code&gt;reducers&lt;/code&gt;, los &lt;code&gt;middleware&lt;/code&gt; (de momento no haremos gran cosa con esto hasta que no veamos luego &lt;strong&gt;Redux Saga&lt;/strong&gt; y escalemos nuestra aplicación), y el &lt;code&gt;devTools&lt;/code&gt;, porque sí, &lt;strong&gt;Redux&lt;/strong&gt; tiene diferentes extensiones en los navegadores como herramientas de desarrollo que nos facilitarán la depuración de nuestra aplicación. Es recomendable habilitarla únicamente en entornos de desarrollo y nunca en producción, pues esto podría dejar al usuario acceder a datos que no queremos que vea. (Tengo que destacar en este punto que no buscamos jamás tener dentro del estado de &lt;strong&gt;Redux&lt;/strong&gt; información como claves y demás, lo que me refiero con datos que no queremos que el usuario vea no se trata de datos críticos, sino información de nuestras apis o de la app que tenemos guardadas y simplemente no mostramos en la app, pero repito, no hay que almacenar claves ni información crítica en &lt;strong&gt;Redux&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;A partir de esta &lt;code&gt;store&lt;/code&gt;, podemos inferir tipos como &lt;code&gt;RootState&lt;/code&gt; para tener acceso al tipado completo de toda la &lt;code&gt;store&lt;/code&gt; desde otros ficheros como los de los selectores, desde nos será esencial para tipar de forma segura.&lt;/p&gt;

&lt;p&gt;Dentro del &lt;code&gt;middleware&lt;/code&gt;, sin entrar mucho en detalle, estamos configurando los &lt;code&gt;middleware&lt;/code&gt; por defecto de &lt;strong&gt;Redux&lt;/strong&gt;, en este caso, el &lt;code&gt;serializableCheck&lt;/code&gt;, que es un &lt;code&gt;middleware&lt;/code&gt; que nos lanza advertencias si estamos almacenando datos no serializados como &lt;code&gt;Set&lt;/code&gt; o &lt;code&gt;Map&lt;/code&gt;, pues &lt;strong&gt;Redux&lt;/strong&gt; recomienda almacenar solo objetos planos convertibles a &lt;strong&gt;JSON&lt;/strong&gt; para facilitar la persistencia, la hidratación etc. En este caso, nosotros lo deshabilitamos. Este paso no es necesario ni mucho menos.&lt;/p&gt;

&lt;p&gt;El fichero debe quedar algo así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nxtmx2bzfcf9umcmorb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nxtmx2bzfcf9umcmorb.png" alt="Image description" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para poder acceder a esta &lt;code&gt;store&lt;/code&gt; ya configurada en nuestra aplicación, es imprescindible añadir el &lt;code&gt;Provider&lt;/code&gt; de &lt;code&gt;react-redux&lt;/code&gt; para envolver nuestra aplicación, en único punto, ya sea en un componente específico para los &lt;code&gt;Providers&lt;/code&gt; de toda la aplicación o en el fichero &lt;code&gt;main&lt;/code&gt;. Este &lt;code&gt;provider&lt;/code&gt; espera como prop la &lt;code&gt;store&lt;/code&gt; que hemos definido, la importamos y listo. Toda la app debe estar envuelta para poder usar &lt;strong&gt;Redux&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqlru6ogly0lilb9wlke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqlru6ogly0lilb9wlke.png" alt="Image description" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esto, ya tenemos la &lt;code&gt;store&lt;/code&gt; inyectada y lista para usarse en nuestra aplicación. Pero, ¿y ahora cómo la usamos?&lt;/p&gt;

&lt;h2&gt;
  
  
  Devtools.
&lt;/h2&gt;

&lt;p&gt;Antes de empezar a ver cómo la usaremos, quiero hacer este pequeño disclaimer para hablar de la herramienta de &lt;strong&gt;Redux Devtools&lt;/strong&gt;, disponible en &lt;strong&gt;Chrome&lt;/strong&gt; y otros navegadores como extensión.&lt;/p&gt;

&lt;p&gt;No es necesario instalar esto para usar &lt;strong&gt;Redux&lt;/strong&gt; en nuestra aplicación, pero es tremendamente útil para el depurado y observar qué ocurre en nuestra aplicación.&lt;/p&gt;

&lt;p&gt;El panel de esta extensión es bastante simple:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwf4ysa0m0gobr5tydb80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwf4ysa0m0gobr5tydb80.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la línea temporal de las &lt;code&gt;actions&lt;/code&gt;, veremos en orden cronológico las acciones que se van lanzando a medida que hagamos interacción con nuestra aplicación. Tenemos un selector de lo que queremos ver en esa acción concreta (al hacer click en cada una de ellas), y la información a mostrar.&lt;/p&gt;

&lt;p&gt;Al clicar en cada acción, podemos ver la propia acción, con el &lt;code&gt;payload&lt;/code&gt; que lleva.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hom7bf1oksh5dwyh8jl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hom7bf1oksh5dwyh8jl.png" alt="Image description" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos ver el estado correspondiente en ese momento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccjne2t4cc2qpm4tckic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccjne2t4cc2qpm4tckic.png" alt="Image description" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y podemos ver la diferencia que ha hecho en el estado esa acción al lanzarse y ser interceptada por el &lt;code&gt;reducer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj8o295yrvh8yk1p458r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj8o295yrvh8yk1p458r.png" alt="Image description" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Existen más opciones dentro de la extensión, podemos ver el estado de nuestra aplicación en formato gráfico con la opción correspondiente en la barra inferior. Podemos ver la información en &lt;strong&gt;JSON&lt;/strong&gt; raw, pausar y resetear el estado, etc.&lt;/p&gt;

&lt;p&gt;Pero con lo explicado, sabemos lo básico para una depuración más o menos óptima. Volvamos a cómo usar la &lt;code&gt;store&lt;/code&gt; y lanzar este flujo de acciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  useDispatch y useSelectors.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;React-redux&lt;/strong&gt; nos pone a disposición dos hooks en los que recae principalmente la responsabilidad del manejo de &lt;strong&gt;Redux&lt;/strong&gt; en nuestra aplicación.&lt;/p&gt;

&lt;p&gt;Es bastante simple de entender, &lt;code&gt;useDispatch&lt;/code&gt; nos devuelve el dispatcher, función que lanza las acciones. &lt;code&gt;useSelector&lt;/code&gt; nos devuelve valores concreto con memoization del estado, pudiendo decidir nosotros a qué queremos acceder. Gracias a esta memoization, nuestro componente se re-renderizará cada vez que este valor cambie. Es importante definir bien a qué dato queremos acceder para evitar re-renders innecesarios y así no echar a perder el rendimiento de nuestra aplicación.&lt;/p&gt;

&lt;p&gt;Viendo la definición que tenemos, vamos a ver de ejemplo muy básico (sin &lt;strong&gt;Saga&lt;/strong&gt; aun ni nada, ultra básico para entender el comportamiento) un componente basiquisimo de la lista de libros y un div para el detalle del libro seleccionado, haciendo también uso de un hook custom con &lt;strong&gt;axios&lt;/strong&gt; para obtener la lista de libro, y luego, explicaremos paso a paso como funciona.&lt;/p&gt;

&lt;p&gt;El hook se ve algo así.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qof6vzc54xj07ymoa4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qof6vzc54xj07ymoa4w.png" alt="Image description" width="800" height="833"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y el componente sería:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95dj90ilwe27np6i7b4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95dj90ilwe27np6i7b4o.png" alt="Image description" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explico paso a paso lo que está ocurriendo aquí:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tenemos un hook que invoca una request con &lt;strong&gt;Axios&lt;/strong&gt; a una api de libros. A partir de un &lt;code&gt;useEffect&lt;/code&gt; y un par de &lt;code&gt;useState&lt;/code&gt;, el hook realiza la request y gestiona el estado de carga con el &lt;code&gt;isLoading&lt;/code&gt; y el error, los cuales devuelve. La magia está en el caso exitoso de la request. Estamos haciendo uso del &lt;code&gt;dispatch&lt;/code&gt;, función que nos devuelve el hook &lt;code&gt;useDispatch&lt;/code&gt; de &lt;code&gt;react-redux&lt;/code&gt;. Estamos lanzando la acción de &lt;code&gt;setBookListSuccess&lt;/code&gt; con la información de la api, seteando de esta manera la lista de libros en nuestro estado, tal como definimos.&lt;/li&gt;
&lt;li&gt;En el componente, hacemos uso de este hook para invocarlo. Pero el hook no devuelve la lista de libros. ¿Cómo accedemos a ella? Hacemos uso del hook &lt;code&gt;useSelector&lt;/code&gt;, el cual recibe una función con el state (mal tipado por mi parte, aquí podríamos usar el &lt;code&gt;RootState&lt;/code&gt; que creamos antes), y accedemos al dato concreto que queremos de el nodo book (definido en el index, dentro del &lt;code&gt;combineReducers&lt;/code&gt;). Lo usamos tanto para obtener la lista de libros como el libro seleccionado, pues tenemos una sección para mostrar más datos del libro que queremos. Hacemos uso del &lt;code&gt;useDispatch&lt;/code&gt; para lanzar la acción de &lt;code&gt;setSelectedBook&lt;/code&gt; al hacer click en cada libro al clickar, o setearlo a null en el botón correspondiente para deshacer esta selección.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Fácil verdad?&lt;/p&gt;

&lt;p&gt;Veamos algunas mejoras que podemos tener.&lt;/p&gt;

&lt;h2&gt;
  
  
  Factoría de selectores.
&lt;/h2&gt;

&lt;p&gt;Si recordáis, al hablar sobre la estructura de directorios propuesta, teníamos una carpeta de selectores. La idea es crear una factoría de selectores por entidad para tener agrupados todas las lógicas de selección de datos de cualquier punto del nodo del estado por entidad/feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux Toolkit&lt;/strong&gt; nos provee una función llamada &lt;code&gt;createSelector&lt;/code&gt;, que nos permite, como su nombre indica, crear selectores a partir del contexto del estado y de otros selectores en sí, optimizando su memoization y pudiendo añadir cualquier lógica adicional, por ejemplo de transformación.&lt;/p&gt;

&lt;p&gt;Os expongo un ejemplo de factoría de selectores para lo que tenemos, con ejemplos, y a continuación explico en detalle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj0uqz0e2mq4gitvu8gf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj0uqz0e2mq4gitvu8gf.png" alt="Image description" width="800" height="873"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En primer lugar, creamos una función como la que usaríamos en el hook &lt;code&gt;useSelector&lt;/code&gt; para obtener el nodo completo de book. En selectores básicos, con la función &lt;code&gt;createSelector&lt;/code&gt;, le damos como parámetros el contexto con &lt;code&gt;rootState&lt;/code&gt;, y accedemos al valor que queramos.&lt;/p&gt;

&lt;p&gt;En el ejemplo de &lt;code&gt;getSelectedBookAuthor&lt;/code&gt; y &lt;code&gt;getSelectedBookTitle&lt;/code&gt;, tenemos el caso de usar otro selector como contexto en la función.&lt;/p&gt;

&lt;p&gt;Y por último, en el caso de &lt;code&gt;getSelectedBookIdAndAuthor&lt;/code&gt;, caso con lógica de devolver un objeto determinado por esos parámetros, recibe varios selectores para poder formar su respuesta.&lt;/p&gt;

&lt;p&gt;Para usar estos selectores, únicamente importas el que quieras en tu componente, y se lo pasas al hook &lt;code&gt;useSelector&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvoxewraxbbk97hlp6s6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvoxewraxbbk97hlp6s6.png" alt="Image description" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A mi parecer, bastante más elegante, y permite tener los selectores bien organizados y no repetir el acceso a ellos ni la lógica que se quiera seguir para procesar los datos del estado.&lt;/p&gt;

&lt;p&gt;¿Y si llevamos el flujo a otro nivel?&lt;/p&gt;

&lt;h2&gt;
  
  
  Potenciando el flujo con Redux-Saga.
&lt;/h2&gt;

&lt;p&gt;Ya hablamos en la introducción sobre &lt;strong&gt;Redux-Saga&lt;/strong&gt;, y lo tenemos instalado. ¿Cómo podemos utilizarlo? Vamos primero a crear una saga, en su carpeta correspondiente, de nuevo, adjunto el ejemplo y luego explico.&lt;/p&gt;

&lt;p&gt;Lo primero que vamos a hacer, es pasar la lógica de loading y error al estado, para gestionarlo todo con &lt;strong&gt;Redux&lt;/strong&gt; y &lt;strong&gt;Saga&lt;/strong&gt;, nos vamos a deshacer totalmente del hook.&lt;/p&gt;

&lt;p&gt;Necesitamos crear una acción dentro del &lt;code&gt;slice&lt;/code&gt; de book para hacer la request, donde se activará el estado de loading. Ya tenemos una acción para el caso de éxito, y también creamos otra para el estado de error. (Las propiedades ya las teniamos definidas en el tipado).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlpzsgo9wdl7g6yz7m48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlpzsgo9wdl7g6yz7m48.png" alt="Image description" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estamos ajustando los valores del loading y del error según el estado que corresponda de la petición, nada más. Nos acordamos de exportarlas y nada más que hacer en el &lt;code&gt;slice&lt;/code&gt;. Habría que setear el &lt;code&gt;isLoading&lt;/code&gt; a false también en la acción del caso de éxito.&lt;/p&gt;

&lt;p&gt;En los selectores, añadimos dos más para el &lt;code&gt;isLoading&lt;/code&gt;, y el &lt;code&gt;isError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Y ahora, a la saga, que sigue la siguiente nomenclatura.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihsiups9cr3pot8t08aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihsiups9cr3pot8t08aj.png" alt="Image description" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí es donde la cosa se ha puesto un poco más complicada de entender, ¿verdad? Os lo explico paso a paso.&lt;/p&gt;

&lt;p&gt;En primer lugar, hacemos un tipado con los tipos de los efectos que vayamos a utilizar en cada saga. Los efectos de las sagas son funciones que se pueden realizar dentro de estas funciones generadoras para una u otra funcionalidad. Los explicaré en cada paso.&lt;/p&gt;

&lt;p&gt;Tenemos las saga principal, donde usamos el efecto &lt;code&gt;spawn&lt;/code&gt;, que crea un proceso independiente para el watcher, o si tenemos varios, de esta forma que si uno muere, el resto no se ven afectados. ¿Y qué es un watcher? Un watcher, es un vigilante, una función generadora que está a la espera de que pase algo, en este caso, una &lt;code&gt;action&lt;/code&gt; en la aplicación. Tenemos definida con el efecto &lt;code&gt;take&lt;/code&gt; la función &lt;code&gt;setBookListRequest&lt;/code&gt;. Este watcher, cada vez que esta &lt;code&gt;action&lt;/code&gt; sea lanzada, ejecutará la función que tiene como segundo parámetro en el &lt;code&gt;take&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se pueden tener varios &lt;code&gt;take&lt;/code&gt; en el mismo watcher, es recomendable un watcher por saga, evidentemente, ya que lo tenemos separado por feature. Existen alternativas al &lt;code&gt;take&lt;/code&gt; como &lt;code&gt;takeLatest&lt;/code&gt; que, si existe una función generadora ejecutandose por una acción, si esta acción se vuelve a lanzar durante la ejecución de esta función, será cancelada. Existen otros como el &lt;code&gt;race&lt;/code&gt;, &lt;code&gt;takeEvery&lt;/code&gt; y tal. Para profundizar en todos los efectos sería necesario otro post, así que vayamos a los básicos, y si te interesa, vas a necesitar seguro estos efectos y te tocará buscarlos, pero para un uso básico quizás no hagan falta.&lt;/p&gt;

&lt;p&gt;Nos hemos quedado en que el watcher ha escuchado la acción &lt;code&gt;setBookListRequest&lt;/code&gt;, por lo tanto, ejecuta la función generadora asociada.&lt;/p&gt;

&lt;p&gt;En esta función, hace uso del efecto &lt;code&gt;call&lt;/code&gt;, que espera recibir de primer parámetro, una promesa, en este caso, la request a &lt;strong&gt;axios&lt;/strong&gt; (podemos hacer nuestras custom promises como servicios, e importarlos aquí, es lo recomendado), y opcionalmente, un segundo parámetro que sería el body por si la request se tratase de un post.&lt;/p&gt;

&lt;p&gt;Una vez termine y la constante de &lt;code&gt;bookList&lt;/code&gt; tenga valor, se hace uso del efecto &lt;code&gt;put&lt;/code&gt;, que es básicamente un dispatcher, lanza acciones. En el caso exitoso, lanzará la acción de success cambiando el estado, añadiendo la lista de libro y cancelando el estado de loading, o en el caso de error, lo correspondiente.&lt;/p&gt;

&lt;p&gt;Nada más, como digo, hay muchos más efectos como el &lt;code&gt;all&lt;/code&gt;, que permite hacer varias ejecuciones de otros efectos en paralelo, para varias requests a api dentro de la misma función en saga (porque si tenemos varias, y las ponemos una detrás de otra con el &lt;code&gt;yield call&lt;/code&gt;, se harán en cascada y no en paralelo), o el mismo &lt;code&gt;put&lt;/code&gt;. Muchas combinaciones posibles harían este post demasiado extenso, y estamos buscando una configuración inicial básica.&lt;/p&gt;

&lt;p&gt;Tenemos ahora que modificar el &lt;code&gt;index&lt;/code&gt; de nuestra &lt;code&gt;store&lt;/code&gt;, para lanzar el &lt;code&gt;middleware&lt;/code&gt; saga, y crear una saga root que haga &lt;code&gt;spawn&lt;/code&gt; de las que nosotros hayamos creado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kb7cmcm0rzd7gbokzk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kb7cmcm0rzd7gbokzk6.png" alt="Image description" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La modificación es tal cual crear &lt;code&gt;sagaMiddleware&lt;/code&gt; con su función correspondiente de &lt;code&gt;createSagaMiddleware&lt;/code&gt;, hacer un &lt;code&gt;concat&lt;/code&gt; con el  &lt;code&gt;default middleware&lt;/code&gt; de &lt;strong&gt;Redux&lt;/strong&gt; para añadirla a nuestra arquitectura, y correr la saga root que hemos hecho haciendo &lt;code&gt;spawn&lt;/code&gt; de todas las que importemos.&lt;/p&gt;

&lt;p&gt;Listo.&lt;/p&gt;

&lt;p&gt;Por último, veamos la modificación correspondiente al componente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5r5742sofja4p9p0v8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5r5742sofja4p9p0v8d.png" alt="Image description" width="800" height="1004"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En el componente, tenemos un &lt;code&gt;useEffect&lt;/code&gt; que lanzará la acción que el watcher de la saga escucha, este lanzará el flujo que hemos implementado y explicado, mientras, el componente mostrará el render del estado de loading, hasta que el flujo termine y tengamos la lista de libros o el error.&lt;/p&gt;

&lt;p&gt;Todo esto, depurable y trackeable de forma muy cómoda en &lt;strong&gt;Redux Devtools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esto es todo lo que se necesita saber para una configuración básica de &lt;strong&gt;Redux&lt;/strong&gt; + &lt;strong&gt;Redux Saga&lt;/strong&gt; en una aplicación de &lt;strong&gt;React&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Recalco que, sobretodo &lt;strong&gt;Redux Saga&lt;/strong&gt;, tiene mucho más contenido para elevar la complejidad de lo que necesitemos realizar en nuestras operaciones de negocio, es un mundo extenso.&lt;/p&gt;

&lt;p&gt;Quiero terminar con una pequeña conclusión, y es que, esta arquitectura permite un escalado y un debuggeo sencillo para aplicaciones con un flujo de datos importante, que vaya a necesitar muchas requests, acciones lanzadas. Es perfecta para aplicaciones grandes, aunque también usables para aplicaciones más pequeñas. Uno de sus mayores puntos negativos es la cantidad de boilerplate que hay que generar para cada cosa que queramos desarrollar, este punto es de hecho, la excusa más usada por los detractores de esta arquitectura, pues genera mucho código, a lo que cachan complejidad y que se puede volver un caos, y es verdad, pero no tiene que pasar si lo mantienes bien, y no hay que desechar una librería con millones de descargo y tanto uso por el boilerplate, si así fuese, tendríamos que deshacernos entonces de frameworks completos como &lt;strong&gt;Angular&lt;/strong&gt;. En la mayoría de los casos, el miedo a usar &lt;strong&gt;Redux&lt;/strong&gt; y &lt;strong&gt;Redux Saga&lt;/strong&gt; viene por desconocimiento, como comenté al principio, tiene una curva de aprendizaje un poco elevada, pero todo es ponerse. Si lo manejas bien, tendrás maestrías en, para mi, la librería más potente y organizada de gestión de estado que existe.&lt;/p&gt;

&lt;p&gt;Si el post resulta interesante, quizás haga un post más avanzado sobre operaciones más complejas con Redux Saga y middlewares personalizados para Redux.&lt;br&gt;
Si has leído hasta aquí, muchísimas gracias por tu tiempo y deja un comentario.&lt;br&gt;
Un saludo.&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/mlcamarena"&gt;@mlcamarena&lt;/a&gt; &lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>reduxsaga</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
