Usando Redux Toolkit y Redux Saga para crear una aplicación con React - Parte I
Desarrollar y mantener aplicaciones con React es algo a lo que aún dedico parte de mi día a día en el ámbito profesional. Lo que más disfruto en la implementación es el manejo del flujo de datos en dichas aplicaciones. Dicho flujo trata de mantener la sincronización entre los diferentes componentes que conforman la aplicación y su comunicación con la fuente de los datos (por ejemplo un servidor web). Para implementarlo utilizamos Redux en combinación con Redux Saga.
Hace algunos de meses mientras investigaba información respecto a Redux Saga me fue complicado hallar ejemplos que utilizaran dicha librería en combinación con Redux Toolkit, que es el estándar de implementación en estos momentos. Es por esto que en esta serie de posts ejemplifico cómo implementar dicha combinación mendiante una sencilla aplicación de cursos en línea.
En esta primera parte desarrollo conceptos básicos sobre las librerías que utilizamos y que permiten sentar las bases para el código que se analizará posteriormente.
La segunda parte muestra la implementación inicial del código.
La tercera parte muestra la implementación de acciones y tests que requieren de interacción con el usuario.
Conceptos básicos
React
React es una popular librería para interfaces de usuario escrita en Javascript. Nos permite crear aplicaciones de usuario de forma fácil utilizando componentes web. Sus principales características son:
- La interfaz de usuario es dividida en sus componentes gráficos.
- Cada uno de los componentes que definimos guardan su propio estado****y son actualizados de forma independiente.
- Cada actualización se ocupa de refrescar sólo la parte afectada por dichos cambios.
Interfaz dividida en componentes: Catálogo y Curso.
Es actualmente muy popular debido a su facilidad de iniciación, a una comunidad enorme de desarrolladores, a una gran cantidad de librerías que nos permiten simplificar su adopción y a la ventaja de que es posible utilizarla en aplicaciones web, de escritorio y móviles (Android y iOS).
Aunque iniciarse en React es muy sencillo las “complicaciones” comienzan cuando se requiere mantener distintos componentes actualizados por un mismo cambio. Una forma de lograrlo efectivamente es manteneniendo un estado global de la aplicación, que permita informar a todos aquellos componentes sobre dicha actualización para que sean capaces de reaccionar ante los cambios.
El componente “Catálogo” afecta la forma en que el componente “Mis Cursos” es mostrado
En la diagrama se muestra cómo una acción efectuada en el componente “Catálogo” tiene como efecto la inclusión de dicho curso dentro del componente “Mis cursos”.
Redux
Redux es una librería en Javascript que nos permite manejar el estado global de una aplicación web. Está diseñada de tal forma que nos sea posible manejar correctamente los flujos de información en todos los componentes.
Para lograr mantener el estado Redux utiliza algunos conceptos básicos:
- Store: es un árbol que guarda los datos de la aplicación.
- Action: es la única forma de modificar el árbol. Una acción es emitida y da como resultado un nuevo estado del árbol.
- Reducer: es una función que especifica cómo la acción va a modificar el árbol.
Store, reduce y action en el estado de la aplicación
En el diagrama anterior se puede observar el patrón en el flujo de la información que es implementado utilizando Redux. Al agregar el “Curso 2” a “Mis cursos” la acción es transmitida al reducer que emite un nuevo valor para que reemplace al actual en la store.
La aplicación de este modelo es conocido como lifting the state o elevar el estado (traducción libre) ya que los cambios en un componente en cualquier lugar de la aplicación terminan en el árbol superior del almacenamiento de datos.
Redux cuenta con una librería adicional llamada Redux Toolkit que es considerada por los desarrolladores de Redux como la forma estándar para implementar el uso de este patrón en la aplicación. La gran motivación para su creación es la complicación que puede presentarse al mantener uniformidad en toda la aplicación.
Esto es algo que he observado que afecta a los equipos de desarrollo software que carecen de documentación sobre el estilo que se utilizará para implementar Redux. Algunos desarrolladores optan por un estilo propio que en algunos casos puede distraer al equipo y hacerlo entrar en debates o tener que hacer reestructuración del código.
Redux Saga
Redux tiene una lógica puramente síncrona, es decir, los cambios en el estado son aplicados en una secuencia continua. En el mundo de las aplicaciones web este tipo de lógica no puede responder correctamente a un flujo de datos que require sincronización eventual, por ejemplo obtener o enviar datos a un servidor web.
Redux Saga es una librería escrita también en Javascript que permite el flujo de datos asíncronos (conocidos como efectos secundarios) dentro de Redux. Esta librería es similar a un hilo de ejecución alterno que sólo maneja dichos flujos y los sincroniza con Redux mediante acciones.
Para poder lograr su cometido esta librería utiliza un tipo de funciones en Javascipt conocidas como generators. Estas funciones pueden pausar su ejecución y reanudarlas posteriormente, permitiendo que puedan ser utilizadas forma más articulada con el código ya que pueden interrumpirlas y continuar cuando sea necesario o cancelarlas por completo.
Como ejemplo podemos crear una función generadora de números enteros del 1 al 3.
function* genNumeros() {
yield 1;
yield 2;
yield 3;
}
Lo primero que se observa es que la función debe ser declarada usando un asterisco: function*
. Posteriormente observamos el uso de la instrucción yield
que indica algo similar a puntos de control en la ejecución de la función.
Para poder utilizar esta función necesitamos almacenarla en una variable que determina su estado: const numeros = genNumeros();
Ejecutar una función de este tipo significa avanzar por los puntos de control que sean necesarios mediante una llamada a next()
.
Función generadora de números del 1 al 3
Como se observa en la imagen la llamada a next()
devuelve un objeto con las propiedades value
y done
que indican el valor devuelto en el punto de control y una bandera para saber si la función ha terminado de ejecutar o no, respectivamente.
En el caso de las Sagas los objetos devueltos en cada yield
son conocidos como effects y son traducidos directamente a instrucciones para ejecutar ciertas operaciones como ejecutar una función asíncrona, despachar una acción en Redux, etc.
Redux Saga permite que mantengamos un modelo mental similar a un flujo de datos síncrono cuando realizamos operaciones asíncronas. También puede manejar correctamente la prevención de flujos no deseados como por ejemplo cuando el usuario hace click dos veces en un botón para realizar una acción.
La Saga se encarga del manejo del flujo asíncrono de datos
Conclusión
Obtener una consistencia en el estado de los componentes al escalar el tamaño de una aplicación con React require mantener un flujo de datos coherente. Una forma de implementar dicho flujo de datos es mediante el uso de un estado global dentro de la aplicación usando Redux.
Es de mi preferencia utilizar Redux y Redux Toolkit en lugar de otras librerías (como Mobx) debido a su implementación puramente funcional, uniformidad, comunidad y cantidad de recursos disponibles para aprender.
Redux tiene una lógica que no soporta los flujos asíncronos presentes en una aplicación web, por lo tanto requiere de una herramienta adicional como Redux Saga para manejar dichos flujos.
En un artículo posterior observaremos el código y sus tests.
Comments:
[…] la primera parte de esta serie se describió el modelo de flujo de datos dentro de una aplicación en React obtenido mediante el […]
#### [Usando Redux Toolkit y Redux Saga para crear una aplicación con React – Parte III – Blog de Raymundo Vásquez Ruiz](https://blog.vasquezruiz.me/react-redux-toolkit-saga-iii/ "") -
[…] la primera parte se describió el modelo de flujo de datos que sigue React al usar Redux y Redux Saga. En la segunda […]