Conoce Redux, el patrón de arquitectura de datos que implementa un flujo de la información sencillo y predecible, adoptado por numerosos frameworks y aplicaciones avanzadas.
Redux es un patrón de arquitectura de datos que permite manejar el estado de la aplicación de una manera predecible. Está pensado para reducir el número de relaciones entre componentes de la aplicación y mantener un flujo de datos sencillo.
Iniciado originalmente por la comunidad de React, como evolución y mejora de las ideas de Flux, Redux se ha convertido en un patrón transversal, capaz de adaptarse a cualquier tipo de librería o framework del lado del cliente. Incluso se podría usar sin necesidad de otro framework Javascript. También se puede ejecutar del lado del servidor o en aplicaciones para móviles, por lo que sus ámbitos de aplicación son muy amplios.
Redux es una librería ligera, de apenas 2 KB de peso, por lo que no resulta ligera también para su ejecución por el motor de Javascript. Su comunidad es muy amplia y ha sido adoptado con éxito por grandes empresas como Netflix.
Beneficios de Redux
En resumen, estos son los beneficios que aporta la aplciación del patrón de Redux.
- Arquitectura escalable de datos
- Mayor control sobre el flujo de datos y el estado de la aplicación
- Estado global e inmutable
Estos beneficios se agradecen en aplicaciones medianas a grandes, en las que el estado de la aplicación cambie constantemente, debido a muchos factores dependientes de diversos componentes.
Cuando la aplicación es compleja es normal que el estado también lo sea y si muchos componentes o piezas de software lo manipulan es normal que llegue un momento en el que se pierde el control sobre el "cuándo, el por qué y cómo" se ha llegado al estado actual. Esta situación se mantiene bajo control mucho mejor gracias a Redux.
Necesidades actuales del frontend también se facilitan en gran medida al usar Redux, haciendo muy fácil necesidades de aplicaciones avanzadas, como congelar el estado actual de una aplicación y entregarla tal cual estaba cuando el usuario vuelve a entrar pasados unos días. Incluso manteniendo el estado de las interfaces de usuario.
Patrón de arquitectura de datos Redux
Existen diversos patrones de arquitectura de datos más o menos populares adoptados a lo largo de la historia del mundo del desarrollo en diversos frameworks. Por ejemplo MVC (Model View Controller) o MVVM (Model View ViewModel) y se pueden encontrar además diversas variantes a éstos. Todos estos patrones especifican cuál es el flujo de la información entre los miembros de una aplicación y cómo transitan los datos de la aplicación entre vistas, modelos, controladores, etc.
Todas las anteriores propuestas tienen una característica que los hace diferentes de Redux, ya que hasta ahora los cambios en el estado de la aplicación podían producirse desde varios elementos del patrón, como vistas o modelos. Este comportamiento produce aplicaciones donde hay mucha interacción entre componentes, lo que eleva su complejidad y dificulta su depuración, mantenimiento, y al final, la escalabilidad.
Facebook, con la intención de simplificar los modelos actuales y hacer más fácil de predecir el flujo de los datos en la aplicación, lanzó Flux. Flux tiene su característica más destacable en el flujo de los datos, ya que éste se realiza siempre en una única dirección.
En resumen, este diagrama nos dice que el "Store" contiene todos los datos de la aplicación, su estado. Los datos siempre van hacia las vistas en una única dirección y para modificar los datos desde la vista se lanzan acciones. Esas acciones, una vez tratadas por el dispatcher, pueden producir un cambio de Estado en el Store, que a su vez viajará hacia la vista.
Flux es solamente una declaración de intenciones, un patrón. Redux es una implementación del patrón, en una librería ligera que podemos usar en cualquier tipo de ambiente de desarrollo, framework, etc.
El diagrama con Redux evoluciona un poco, pero mantiene la esencia comentada para Flux: el flujo unidireccional de los datos y la necesidad de solicitar cambios en los mismos por medio de acciones.
Además se agregan los "Reducers" que no son más que funciones puras (enseguida explicamos ese concepto) que se encargan de procesar las acciones y generar un nuevo estado, en el Store.
Tres principios básicos de Redux
Debemos grabar a fuego en nuesrta memoria los tres principios fundamentales de Redux:
- Store como única fuente de la verdad
- El estado (State) es de solo lectura
- Los cambios se hacen por medio de acciones (actions) y funciones puras (reducers)
Store como única fuente de la verdad
El store es el estado al que todos atienden. El único estado de la aplicación válido está en el store. Los componentes que necesiten conocer al estado acudirán al store para recuperarlo.
Los datos del store viajan a los componentes en una única dirección. Esto se traduce en que el data-binding que usaremos para enviar al store hacia los componentes será 1-way, de una única dirección.
El estado (State) es de solo lectura
El estado en Redux es un único objeto Javascript, organizado en modo de árbol (como JSON), que contiene todos los datos que la aplicación va a manejar.
El estado de una aplicación podría parecerse a algo como:
{
heroe: "Super Yo",
supervillanosPreferidos: ["Joker", "Magneto"],
vidas: 5,
nivel: 1
}
Los componentes que manejan los datos del estado solo leen los datos, no los manipulan. En el caso que ocurra una manipulación permanece sólo en ese componente y no se transfiere al resto de la aplicación.
Para poder alterar el estado de la aplicación se usarán acciones. Las acciones (actions) representan la única vía de producirse una modificación en el estado global de la aplicación.
Las acciones son descriptivas de aquella modificación que se desea realizar y se representan mediante un objeto Javascript. Ellas contienen, como mínimo, el tipo de acción que se desea realizar. Por ejemplo "subir un nivel" o "restar una vida". Además, hay acciones que requieren describirse con parámetros adicionales, como podría ser el nombre de un supervillano para agregar a la lista de villanos preferidos.
Esta es la forma que podrían tener las acciones.
{ type: "INCREMENTAR_NIVEL" }
{ type: "DECREMENTAR_VIDA" }
{ type: "ANADIR_VILLANO", nombre: "Dr. Doom" }
Como hemos dicho, las dos primeras acciones no requieren ningún dato adicional, porque se entiende que tienen que sumar o restar una unidad, pero en la acción de añadir un villano necesitamos indicar el nombre.
Los cambios se hacen por medio funciones puras
Una vez emitidas las acciones, estas se procesan por medio de funciones puras, a las que se denominan "reducers".
El reducer siempre recibe dos parámetros: una acción y el estado anterior. Contiene la lógica para procesar tales acciones y como consecuencia de ellas puede modificar al estado. Una vez ejecutada la lógica, el reducer devuelve el nuevo estado.
Básicamente nuestros reducers se podrían parecer a un código como este, en el que tenemos un switch con diferentes case para cada acción. Aunque lógicamente, cuando la aplicación se hace grande se podría organizar el código de otra manera, por ejemplo haciendo una función que se encargue de mantener cada parte del estado.
function reducers(state, action) {
switch (action.type) {
case 'INCREMENTAR_NIVEL':
// Ejecutar la lógica
// Devolver un nuevo estado
case 'DECREMENTAR_NIVEL':
// ...
default:
return state
}
}
El concepto de reducers como "funciones puras" quiere decir que éstas no provocan ningún tipo de efecto colateral. Se encargan de modificar al estado, ellas mismas, y nada más. Esto quiere decir que no modifican directamente partes de la interfaz, no almacenan en base de datos, no producen solicitudes Ajax a servicios web, no llaman a otras funciones para realizar su trabajo, etc.
Este sería el diagrama de un reducer.
Redux Toolkit
Antes de terminar el artículo sobre Redux queremos mencionar otra herramienta, también creada por el equipo de Redux. Se trata de Redux Toolkit, una biblioteca paralela que permite desarrollar los artefactos necesarios para trabajar con Redux de una manera más sencilla y rápida.
Si había alguna desventaja importante en el trabajo con Redux, destacada de manera frecuente por los desarrolladores, era la complejidad que introducía en el flujo de desarrollo, lo que hacía que esta librería tuviese a menudo detractores. Redux Toolkit vino a solucionar esta situación, aportando numerosas utilidades que reducen el código necesario para utilizar Redux y, a la vez, evita introducción de errores en la programación.
Redux Toolkit es actualmente una recomendación para cualquier aplicación que vaya a incorporar Redux para la gestión del estado, independientemente de su tamaño. Si quieres saber más sobre esta librería te recomendamos que entres en la categoría dedicada a Redux Toolkit.
Conclusión
Hemos conocido los conceptos clave de Redux, con lo que esperamos puedas hacerte una idea de esta arquitectura de datos y valorar la posibilidad de incorporarla dentro de tus propias aplicaciones.
El siguiente paso sería implementar un ejemplo usando esta librería, pero para ello era fundamental aclarar los conceptos con los se va a trabajar, pues así en adelante el código quedará mucho más claro.
Para concluir esta introducción, de momento, puedes ver el siguiente diagrama. Muestra de una manera muy visual cómo la arquitectura de componentes varía con y sin Redux. A un lado tenemos el diagrama de componentes y flujo de los datos en una arquitectura tradicional, con data-biding de una y dos direcciones, donde muchos componentes son capaces de manipular el estado. Al otro lado tienes una arquitectura de componentes basada en Redux, donde hay un store que alimenta a todos los componentes y donde cualquier modificación se realiza por medio de una acción.
Como referencias se debe consultar la documentación del propio Redux y si lo deseas, la clase gratuita de Redux que nos ofreció Nicolás Molina en EscuelaIT para el curso de Redux con Angular (Al que le he tomado prestadas las imágenes para ilustrar este artículo).
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...