Saltar al contenido

Construyendo una aplicación Redux con Angular 2 Tutorial

Ahora que conoces los conceptos principales, probablemente te preguntes cómo se unen en una aplicación de Angular 2. Para ilustrar cómo funciona Redux, vamos a construir una simple herramienta de contabilidad financiera que hará un seguimiento de sus transacciones usando la arquitectura Redux. Presentará operaciones que añadirán o deducirán dinero de una cuenta imaginaria. Más tarde, vamos a añadir una forma de ver su saldo actual y algunas estadísticas adicionales.

Configuración

Usaremos angular-cli para configurar el proyecto:

Construyendo una aplicación Redux con Angular 2 Tutorial
Construyendo una aplicación Redux con Angular 2 Tutorial
12 ng new financials_app cd financials_app

bash

ngrx/store es un contenedor estatal construido específicamente para aplicaciones de Angular 2. Va a proporcionar las utilidades y los bloques de construcción para la arquitectura del Redux.

1npminstall @ngrx/core @ngrx/store --save

bash

Opcionalmente , también puedes instalar Bootstrap para que la aplicación se vea bien y bien estructurada:

1npminstall[correo electrónico protegido]

bash

Añade las siguientes líneas al angular-cli.json.

En la matriz app.scripts, como una propiedad del objeto:

12345 "scripts":["../node_modules/jquery/dist/jquery.js","../node_modules/tether/dist/js/tether.js","../node_modules/bootstrap/dist/js/bootstrap.js"],

json

En el conjunto de estilos de aplicaciones:

1234 "styles":["../node_modules/bootstrap/dist/css/bootstrap.css", "styles.css"]

json

Su primer reductor

Lo primero que hay que hacer en una aplicación Redux es definir tu tienda y empezar a colocarle reductores. Para la primera iteración de la aplicación, añadiremos el estado de las operaciones financieras.

En su aplicación Angular 2, haga un nuevo directorio que contenga los reductores de su aplicación:

12cd src/app mkdir common

bash

Primero, hagamos un modelo de nuestra operación financiera:

12345678//src/app/common/operation.model.tsexportclassOperation{ id:number; amount:number; reason:string;constructor(){}}

ts

Definición de una función reductora

A continuación, cree un archivo que contenga las definiciones de las acciones y el reductor para las operaciones financieras:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950//src/app/common/operations.tsimport{AcciónReductora,Acción,Estado}de$0027@ngrx/store$0027;import{Operación}de"./operación. modelo";//definiciones de las acciones que alteran el estadoexportconstADD_OPERATION=$0027Agregar una operación$0027;exportconstREMOVE_OPERATION=$0027Eliminar una operación$0027;exportconstINCREMENT_OPERATION=$0027Incrementar una operación$0027;exportconstDECREMENT_OPERATION=$0027Disminuir una operación$0027;//el estado inicial de la operaciónsconst initialState: Estado=[];// las operacionesFunción reductora: una función pura que se encarga de mantener el//el estado de las operaciones financieras de su almacenexportaciónconst operacionesReductor:AcciónReductor=(estado = inicialEstado, acción:Acción)=;{conmutación(acción. type){//En Redux, no se puede mutar el estado. En este caso, utilizar .push(), .pop(),// .shift() o .unshift() va en contra de la convención.caseADD_OPERATION://Action typeconst operation_Operation= action.payload;//el contenido de una operaciónretorno[... state, operation ];caseOPERACIÓN_INCREMENTACIÓN:const operation =++acción.payload.amount;return state.map(item=>{retorno item.id=== action.payload.id?Object.assign({}, item, operation): item;});caseOPERACIÓN_DECRECREMENTACIÓN:const operation =--acción. payload.amount;//actualizar el estado creando un nuevo objeto usando Object.assign()return state.map(item=§;{return item.id=== action.payload.id?Object.assign({}, item, operation): item;});caseREMOVE_OPERATION:return state.
ts

El estado del reductor es un conjunto de operaciones financieras. Por cada acción que se envía al reductor (o, para decirlo de forma sencilla, cada vez que se llama a la función del reductor), un operador del interruptor crea un nuevo estado , dependiendo del tipo de acción, con los cambios aplicados. Si el tipo de acción no coincide con ninguna de las acciones definidas, simplemente se devuelve el estado.

Note que el estado es inmutable . En lugar de cambiar el conjunto de operaciones, creamos una copia de él y aplicamos los cambios a la nueva copia.

Iniciando la tienda

A continuación, pon el reductor en la tienda.

123456789101112131415161718192021/// src/app.module.tsimport{AppComponent}from$0027./app.component$0027;import{StoreModule}from"@ngrx/store";import{operationsReducer}from". /común/operaciones";/importar el reductorimportar{Módulo Común}de"@angular/común";@NgModule({ bootstrap:[AppComponent], declaraciones:[AppComponent//. ..], importa:[// import StoreModule//...StoreModule.provideStore({ operaciones: operacionesReducer })//provideStore acepta un objeto con reductores.],})exportclassAppModule{constructor(){}}

ts

En esta etapa de la aplicación, sólo hay una parte del estado y, por consiguiente, sólo un reductor. Sin embargo, en etapas posteriores, tendremos múltiples reductores y utilizaremos combineReductores para proporcionar una ayuda para el envío de acciones. combineReductores simplemente actúa como una ayuda para combinar todos los estados devueltos de los reductores en una única entidad que representará el almacén de la aplicación.

Poniendo las operacionesReductores como argumento en provideStore, puedes acceder al estado de las operaciones en cualquier lugar de la aplicación importando Store desde @ngrx/store. Así es como puedes hacerlo:

Proyección del estado

1234567891011121314151617//src/app/app.component.tsimport{Component,ViewEncapsulation}de$0027@angular/core$0027;import{Operación}de"./común/operación. modelo";importar{Estado,Tienda}de"@ngrx/store";@Componente({ selector:$0027app-root$0027, plantilla:`{{{operaciones | json }}`})exportclaseAplicaciónComponente{operaciones públicas:Matriz<Operación select($0027operations$0027).subscribe(state====estado.operations=estado)}}

ts

Inyectando la tienda y usando store.select(), puedes acceder a uno de los estados de la aplicación (desde los reductores que pones en provideStore(). En este caso, sólo tenemos operaciones. El store siempre devuelve un observable, por lo que hay que suscribirse a él, o, si lo pasas en un componente hijo, utilizar el pipe async (más adelante se dará un ejemplo).

Ve a tu terminal y construye la aplicación:

1 ng serve

bash

Abra su navegador y vaya a http://localhost:4200.

En este punto, todo lo que verán es una matriz vacía ([]), procedente de la tubería json que se está utilizando en las operaciones.

Acciones de despacho

El estado de la tienda se actualiza a través de acciones predefinidas, que se despachan desde los eventos de usuario y se utilizan como entrada para las funciones reductoras.naturalmente, la primera acción que vamos a implementar en la aplicación será la acción ADD_OPERATION que, como su nombre indica, va a adjuntar una nueva operación financiera al conjunto de operaciones.

123456789101112131415161718192021222324252627// src/app/app.component.tsimport{ADD_OPERATION,}from"./common/operations";//importar el tipo de operación//... exportclassAppComponent{public id:number =0;//simular IDoperaciones públicas:Array<Operation;//iniciar una nueva clase de operación instancepublic operation_Opeation=newOperation();constructor(privado _store:Store<State;/){ _store. select($0027operations$0027).subscribe(state===;this.operations= state)}addOperation(){//utilizar la función dispatch() para enviar una acción con tipo y carga útilesta._store.dispatch({type:ADD_OPERATION, payload:{ id:++this.id,//simular los incrementos de ID reason:this.operation.reason, amount:this.operation.amount}});}

javascript

La acción se despacha usando la función incorporada dispatch() en el almacén proporcionado por @ngrx/store. Como argumento, enviamos un tipo de acción válida que hemos definido previamente en src/app/common/operations.ts.

Pero, ¿cómo va a introducir el usuario la información sobre la operación financiera? Añadamos un formulario que permita al usuario rellenar el modelo de operación con información

123456789101112131415161718192021222324252627// src/app/app.component.ts @Component({ template:`<div <div <form > <div <div <div <input type="text" [(ngModel)]="operation. amount" name="amount" placeholder="Amount"> <div </div> </div> <div <input type="text" [(ngModel)]="operation. reason" name="reason" placeholder="Reason"> </div> <button type="submit" (click)="addOperation()" btn-primary">Add operation</button> </form> </div; </div; {{operations | json}}`//...})

javascript

En la plantilla, simplemente usamos [(ngModel)] para vincular los atributos de la Operación a los campos de entrada y llamamos al addOperation() cuando se pulsa el botón.

Si intentamos insertar algo en el estado ahora mismo, lo verás aparecer en la plantilla como JSON. Esto no es una experiencia agradable para el usuario, y limita nuestra capacidad de añadir más funcionalidad. Para contrarrestar, hagamos las operaciones en una lista:

En lugar de {{i}} {i1}operaciones} {i1}json}}, ponga lo siguiente.{i}

12345678910<div;³³³$0027div;³³³$0027ul;³³³$0027li*ngFor="let operation of operations"[ngClass]="{$0027list-group-item-success$0027: operation.amount > 0 ,$0027list-group-item-danger$0027: operation.
html

Usando *ngFor y algunos estilos de boostrap incorporados, ahora vemos una operación financiera que aparece cada vez que añadimos una.

Lo que acabamos de implementar es un ciclo completo de una simple acción. Haciendo clic en el botón Add Operation , enviamos una acción ADD_OPERATION a la tienda, que llamó al reductor de operaciones . El reductor aplicó la acción y devolvió el nuevo estado en la tienda. Las operaciones observables recibieron un nuevo valor del estado y lo mostraron en la plantilla.

Añadamos el resto de las acciones - REMOVER_OPERACIÓN , ICREMENT_OPERACIÓN , DECREMENT_OPERACIÓN. Aquí está el código completo de la clase AppComponent:

1234567891011121314151617181920212223242526272829303132333435363738/// src/app/app.component.tsimport{ADD_OPERATION,REMOVE_OPERATION,INCREMENT_OPERATION,DECREMENT_OPERATION}de". /común/operaciones";exportclassAppComponent{public id_number=0;//simulando IDoperaciones públicas:Array<Operación dispatch({type:ADD_OPERATION, payload:{ id:++this.id,//simulando ID incrementos razón:esta.razón.operación, cantidad:esta.cantidad.operación}});}/añadiendo REMOVE_OPERATIOn , INCREMENT_OPERATION , DECREMENT_OPERATIONincrementOperation(operation){this._store. Operación de reducción (operación) (este._almacén) (tipo: operación de reducción, carga útil: operación)) (este._almacén) (tipo: operación de reducción, carga útil: operación) (este._almacén) (borrar operación) (este._almacén) (tipo: operación de eliminación, carga útil: operación) (este._almacén) (

)
ts

El resto de las acciones siguen el mismo patrón enviando un tipo de acción y la propia operación como carga útil. En la plantilla, sólo tenemos que añadir los botones correspondientes para activar nuestras acciones. Añadamos un grupo de botones en el .list-group-item div para las acciones que se pueden realizar en una sola operación.

123456789101112<!--src/app/app.component.ts --;<!-- resto de la plantilla --;li*ngFor="let operation of operations"[ngClass]="{$0027list-group-item-success$0027: operation.amount > 0 ,$0027list-group-item-danger$0027: operation.amount < 0 }"<h3>$ {{{{operación. amount}}</h3 ]p ]span ];Razón:www. operación. razón}}</promedio de la div.; botón(click)="incrementoOperación(operación) "+</botón
html

¡Ve a http://localhost:4200 y juega con tu aplicación Redux!