> Manuales > Manual de Polymer 2

Qué es Uniflow, un patrón de arquitectura para aplicaciones Polymer 2 inspirado en el patrón Flux y Redux.

En este artículo vamos a ofrecer una introducción a Uniflow, un nuevo complemento para las aplicaciones Polymer, con el que podremos realizar una arquitectura de aplicación más depurada, escalable y mantenible.

Uniflow de Polymer toma las ideas y conceptos lanzados por Flux para aplicaciones ReactJS. También sería similar a Redux, pero directamente pensada para usar en Polymer 2. Sin embargo, hay que aclarar que Uniflow y Polymer no están desarrollados por el mismo equipo. A pesar que Uniflow Polymer es también un proyecto de Google, sus desarrolladores no pertenecen directamente al equipo de Polymer. Aunque, dicho sea de paso, el equipo de Polymer ha prestado bastante atención a Uniflow y ha depositado muy buenos comentarios en la comunidad.

Por qué nace Uniflow

Desarrollar una aplicación Polymer es una experiencia sencilla para el programador. Sus mecanismos de binding y el tratamiento de eventos son excelentes mecanismos para comunicación entre componentes, pero a veces, si no se mantiene una organización, el código puede hacerse difícil de mantener.

Sobre todo en proyectos grandes, donde la complejidad aumenta y se tiene muchos componentes que se relacionan entre sí, se puede hacer difícil la depuración del código y la ampliación de funcionalidad.

Uniflow propone una arquitectura que, una vez implementada permite una asimilación más sencilla del esquema de relaciones entre componentes y con ello facilita el mantenimiento y la comprensión del flujo de los datos dentro de la aplicación.

Qué es Uniflow

Básicamente son una serie de mixins, creados para mantener el estado de la aplicación de una manera controlada. Aplicados a los elementos de la aplicación estos mixins nos permiten disponer de un API específicamente pensado para facilitar la colaboración entre componentes, aplicando el patrón "Flux".

El patrón Flux, popularizado por React, tiene como característica fundamental el flujo de datos unidireccional dentro de la aplicación.

Dentro de uniflow existe un componente que recibe todas las acciones y es capaz de manipular el dato. Una vez manipulado, el valor nuevo del dato viaja por data-binding a los componentes hijos, para ser representado en todos los lugares de la aplicación donde sea usado.

Puedes encontrar más información en la documentación de Polymer Uniflow.

Ejemplo de uso de Uniflow

Para aprender más sobre la implementación de Uniflow en el marco de una aplicación Polymer, vamos a realizar un sencillo proyecto, donde podamos aplicar algunos de los mixins que nos facilita esta librería.

Vamos a mantener sencilla esta primera aproximación, para facilitar las cosas. Por ese motivo en nuestra aplicación ni siquiera vamos a usar todos los mixins que tenemos disponibles en Polymer Uniflow. Sin embargo, confiamos que esta primera aproximación sirva para entender cuál es el uso de Uniflow y cómo implementa el flujo de información en nuestra aplicación.

El ejemplo que vamos a crear es un sencillo contador de clics. Solo tendremos un botón y un texto que nos dice el número de clics realizados sobre el botón. Al hacer clic sobre el botón se incrementará en uno el contador, y se representará inmediatamente en la aplicación.

Crearemos un nuevo proyecto de Polymer. Comando "polymer init" en el Polymer CLI. Podemos escoger el template de aplicación básico, para no despistarnos con cosas que no tengan que ver con el propio Uniflow.

Instalamos la librería uniflow-polymer

bower install --save google/uniflow-polymer

Estado de la aplicación

Existe un único lugar donde se almacena el estado de la aplicación. Este lugar corresponde generalmente al componente raíz de la aplicación.

El estado es como cualquier otra propiedad. Será un objeto que contendrá una cantidad de subpropiedades con los datos que queremos manejar como estado de la aplicación. No necesitamos declarar la propiedad, puesto que los mixins que iremos incluyendo ya lo hacen por nosotros. Sin embargo, la podemos inicializar en el método ready() de nuestro componente raíz.

ready() {
  super.ready();
  this.set('state', {
    clics: 0
  });
}

De manera general, a lo largo de todo el proyecto, si queremos traspasar el estado de un componente a otro, lo hacemos por medio de binding de 1 sola dirección, en Polymer expresado por los corchetes [[]].

<muestra-clics clics="[[state.clics]]"></muestra-clics>

Mixin ApplicationState

El componente raíz de la aplicación, o aquel que deba manejar el estado de manera global, debe usar el mixin "ApplicationState".

Este mixin solo estará presente en un único componente!

Primero lo tendrás que importar:

<link rel="import" href="../../bower_components/uniflow-polymer/application-state.html">

Luego se declara el uso del mixin en la cabecera de la clase del componente.

class ClicsApp extends UniFlow.ApplicationState(Polymer.Element) {

Emisores de acciones

Existirán componentes que deban modificar el estado de la aplicación. Sin embargo no lo harán por ellos mismos, ya que para modificar el estado siempre se debe realizar la invoación de una acción.

Todos los componentes que deban modificar el estado serán emisores de acciones. Para ello emitirán acciones que en el fondo son eventos, que suben hasta el componente raíz usando la burbuja de eventos del navegador.

Los componentes que emiten acciones deben usar el mixin "ActionEmitter", que está entre el conjunto de clases que nos ofrece Polymer Uniflow.

Primero debe importarse:

<link rel="import" href="../bower_components/uniflow-polymer/action-emitter.html">

Luego tendremos que declarar el uso del mixin en el componente que va a emitir acciones:

class BotonClic extends UniFlow.ActionEmitter(Polymer.Element) {

Por último, se lanzan las acciones. Al lanzar la acción debemos de indicar algunos datos. Al menos será necesario enviar el tipo de la acción que se desea ejecutar.

this.emitAction({
  type: 'AGREGAR_CLIC'
});

Componente "Action Dispatcher"

Ahora vamos a hablar del componente Action Dispatcher, que se encarga de procesar las acciones. Este es un componente no-representacional (que no tiene ningún elemento visual en su template para presentación) y generalmente será un hijo directo del componente raíz de la aplicación. Podría apoyarse en otros componentes para realización de las acciones, aunque de momento no es el caso porque tenemos una sola acción a implementar.

Este componente recibe el estado de la aplicación, enviado por doble binding desde el componente raíz.

<contador-clics-action-dispatcher state="{{state}}"></contador-clics-action-dispatcher>
Nota: Este es el único sitio donde usamos doble binding del estado de la aplicación, ya que el action dispatcher es el único sitio donde queremos modificarlo. Para el resto de los componentes donde pasemos el estado deberíamos usar binding de una sola dirección.

Mixin UniFlow.ActionDispatcher

En el componente Action Dispatcher se debe incluir el mixin UniFlow.ActionDispatcher.

Comenzamos importando:

<link rel="import" href="../bower_components/uniflow-polymer/action-dispatcher.html">

Tenemos que declarar el mixin en la cabecera de la clase del componente:

class ContadorClicsActionDispatcher extends UniFlow.ActionDispatcher(Polymer.Element) {

En el action dispatcher encontraremos un método para implementar cada acción. El método tiene el mismo nombre de la acción implementada.

AGREGAR_CLIC(details) {
  this.set('state.clics', this.state.clics + 1);
}

En los métodos de las acciones está permitido modificar el estado. Realmente, es el único sitio donde se debería hacer. Como el estado definido en el action dispatcher tiene un doble binding con el estado general, definido en la raíz de la aplicación, cualquier modificación se trasladará a todos los componentes de la aplicación.

Nombres de las acciones definidos de manera global

El nombre de la acción lo tenemos escrito a fuego en el código y puede ocurrir que se repita varias veces a lo largo de la aplicación. Por ello sería una buena idea declararlos de manera global para toda la aplicación.

Lo podemos hacer de diversas maneras, por ejemplo, yendo a lo sencillo, en un archivo de Javascript plano, que incluiremos en el index.html.

Este sería el código para la definición de los nombres de las acciones, a través de un objeto que contenga todas las declaraciones de nombres de funciones.

window.contadorClics = window.contadorClics || {};
contadorClics.actions = {
  AGREGAR_CLIC: 'AGREGAR_CLIC'
}

Este código lo podremos situar en un fichero independiente llamado "actions.js" y por supuesto tiene que estar enlazado en algún sitio. Habíamos dicho que en el index.html podría servir:

<script src="scripts/actions.js"></script>

Uso de los nombres de acciones

Una vez definidos los nombres de las acciones podremos usarlos, tanto al invocar las acciones como al implementarlas.

Invocamos las acciones así (recuerda que esto lo haces en el componente que habíamos definido con el mixin UniFlow.ActionEmitter):

this.emitAction({
  type: contadorClics.actions.AGREGAR_CLIC
});

Ahora podemos implementar las acciones así (Recuerda que esta implementación se encuentra en el componente que hemos llamado "Action Dispatcher".

[contadorClics.actions.AGREGAR_CLIC](details) {
  this.set('state.clics', this.state.clics + 1);
}

Conclusión

Lo visto en este artículo son las líneas generales de uso de Polymer 2 Uniflow. Si tienes una idea al menos ligera sobre el desarrollo de aplicaciones con Polymer seguramente puedas construir tu propio ejemplo a partir de estas explicaciones.

Además, sabemos que apreciarás ver el código completo de esta aplicación, para resolver posibles dudas. Lo tienes en Github: https://github.com/deswebcom/contador-clics-polymer-uniflow-ejemplo

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual