Está en la página 1de 62

Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

ichi.pro

Cómo implementar la tienda NGRX en


aplicaciones angulares
47-60 minutes

1 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Foto de Meriç Dağlı en Unsplash


NGRX Store es una biblioteca de administración de estado para las
aplicaciones angulares. Solíamos tener la gestión de sesiones en
el servidor antes de las aplicaciones de una sola página en las que
mantenemos una sesión en todas las solicitudes de página.
Cuando se trata de aplicaciones de una sola página, es difícil
mantener el estado. Se vuelve más fácil con la tienda NGRX.

Comencemos de inmediato y veamos cómo podemos configurar la


administración de estado con Angular usando NGRX Store.

Aquí están las cosas que cubriremos en este artículo.

Proyecto de ejemplo

Cómo funciona

Conceptos básicos de NGRX

Prerrequisitos

Instalación

Implementación de API

Implementación de NGRX

Implementación angular

2 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Resumen

Conclusión

Echemos un vistazo al proyecto de ejemplo. Tenemos una


aplicación simple en la que podemos iniciar sesión, registrarnos y
agregar tareas, eliminar tareas y editar tareas, etc. El estado
completo de la aplicación se mantiene con NGRX. Tenemos
acciones, efectos, reductores, etc. Veremos todos en este ejemplo.

3 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Proyecto de ejemplo
Aquí está el proyecto de ejemplo en GitHub donde puede clonarlo
y ejecutarlo en su máquina local.

// clone the project


git clone https://github.com/bbachi/angular-ngrx-
example.git
// Run the API
cd api
npm install
npm run dev
// Run the Angular App
cd ui
npm install
npm start

NGRX es una herramienta de gestión de estado inspirada en redux


para las aplicaciones angulares. Cuando su aplicación se hace
cada vez más grande, la comunicación se vuelve difícil de manejar.
NGRX proporciona un flujo de datos unidireccional y una única
fuente de información para toda la aplicación.

Los componentes que conocen la tienda se denominan

4 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

componentes inteligentes y los componentes que no conocen la


tienda se denominan componentes tontos. Si observa el siguiente
diagrama, todos los componentes inteligentes envían los datos a la
tienda y reciben datos de la tienda promoviendo un flujo de datos
unidireccional para toda la aplicación.

Tienda NGRX
Actualizar o volver a cargar la página perderá todo el estado de la
aplicación. Ahí es cuando entra en juego el almacenamiento local.
El estado completo de la aplicación se serializa y se guarda en el
almacenamiento local justo antes de volver a cargar la página y
todo el estado se deserializa del almacenamiento local y se

5 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

reinicializa el estado de la aplicación. A esto se le llama rehidratar


la tienda.

A veces tenemos que hacer llamadas a la API para obtener los


datos de la aplicación. Siempre que la tienda necesita datos de la
API de backend, utiliza efectos NGRX para realizar una llamada a
la API y recuperar los datos y actualizar la tienda. Veremos esto en
detalle en secciones posteriores.

Conceptos básicos de NGRX

NGRX Store está inspirada en Redux, que proporciona


administración de estado para las aplicaciones angulares y
funciona con RXJS, lo que aumenta el rendimiento y la
consistencia de las aplicaciones angulares.

¡¡Vamos a ver cómo funciona!!.

6 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Tienda NGRX en detalle


Las acciones se envían desde los componentes y servicios. Estos
son solo eventos únicos con tipo y carga útil y se pueden enviar a
la tienda

Los reductores son las funciones puras que toman la última


acción y el estado actual y devuelven el nuevo estado.

Los selectores son las funciones puras que nos permiten


seleccionar una porción del estado.

El Estado se puede acceder a través de tienda observables en


componentes y servicios

Los efectos NGRX son las funciones que se pueden ejecutar para
obtener los nuevos datos para el estado. Por ejemplo, si su
componente necesita nuevos datos de la API, el componente envía
una acción, los reductores invocan los efectos y servicios para

7 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

obtener los nuevos datos, el reductor devuelve el nuevo estado con


esos datos de la API.

Hay algunos requisitos previos para este artículo. Necesita tener


nodejs instalado en su computadora portátil y cómo funciona http.
Si desea practicar y ejecutar esto en su computadora portátil, debe
tenerlos en su computadora portátil.

NodeJS

CLI angular

Mecanografiado

VSCode

ngx-bootstrap

NGRX

Cómo desarrollar y compilar una aplicación angular con NodeJS

Instalación

Cuando se trata de NGRX, necesitamos instalar un montón de


bibliotecas. Instalemos todas las siguientes bibliotecas para NGRX.

// install NGRX dependencies

8 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

npm install @ngrx/{effects,entity,router-


store,store,store-devtools} --save
npm install ngrx-store-freeze ngrx-store-
localstorage --save

Implementemos la parte API de toda la aplicación paso a paso. La


API está construida con un marco Nodejs y express. Tenemos un
inicio de sesión, registro, agregar tareas, eliminar tareas, editar
tareas y obtener operaciones de tareas.

API de NodeJS de llamada angular


Si observa el diagrama anterior, Angular con la tienda NGRX llama
a la API NodeJS. Aquí está el archivo server.jsque tiene todas

9 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

las operaciones y escucha en el puerto 3080.

const express = require('express');

const path = require('path');

const app = express(),

randomId = require('random-id')

bodyParser = require("body-parser");

port = 3080;

const idlen = 10;

// place holder for the data

const users = [];

let tasks = [];

app.use(bodyParser.json());

app.use(express.static(path.join(__dirname, '../ui/build')));

app.get('/api/users', (req, res) => {

10 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

console.log('api/users called!')

res.json(users);

});

app.post('/api/user', (req, res) => {

const user = req.body.user;

console.log('Adding user:::::', user);

users.push(user);

res.json("user addedd");

});

app.post('/api/login', (req, res) => {

const user = req.body.user;

console.log('Adding user:::::', user);

const usersFound = users.filter(usr => usr.email === user.email


&& usr.password === user.password);

if (usersFound.length > 0) {

11 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

res.json({status: true, message: 'user found', user:


usersFound[0]});

} else {

res.json({status: false, message: 'user not found'});

});

app.post('/api/signup', (req, res) => {

const user = req.body.user;

console.log('Adding user:::::', user);

users.push(user);

res.json({status: true, numberOfUsers: users.length});

});

app.get('/api/tasks', (req, res) => {

res.json(tasks);

});

12 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

app.post('/api/task', (req, res) => {

const task = req.body.task;

const id = randomId(idlen);

task.id = id;

tasks.push(task);

res.json({status:true, taskId: task.id, message: `task ${task.id}


addedd`});

});

app.delete('/api/task/:id', (req, res) => {

console.log('deleting task:::', req.params.id);

const id = req.params.id;

tasks = tasks.filter(tsk => tsk.id !== id)

res.json({status:true, message: `task ${id} deleted`});

});

app.put('/api/task', (req, res) => {

13 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

const task = req.body.task;

tasks = tasks.map(tsk => {

if(tsk.id === task.id) tsk = task;

return tsk;

});

res.json({status:true, message: `task ${task.id} edited`});

});

app.get('/', (req,res) => {

res.sendFile(path.join(__dirname, '../ui/build/index.html'));

});

app.listen(port, () => {

console.log(`Server listening on the port::${port}`);

});

Estamos usando nodemon en el entorno de desarrollo para


observar cualquier cambio de archivo y reiniciar el servidor. Todo lo

14 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

que necesita para ejecutar este comando npm run devpara


iniciar el servidor nodejs en el modo de desarrollo.

"name": "api",

"version": "1.0.0",

"description": "",

"main": "index.js",

"scripts": {

"start": "node server.bundle.js",

"build": "webpack",

"dev": "nodemon ./server.js localhost 3080"

},

"keywords": [],

"author": "",

"license": "ISC",

15 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

"dependencies": {

"express": "^4.17.1",

"random-id": "^1.0.4"

},

"devDependencies": {

"nodemon": "^2.0.4"

Aquí está la demostración donde inicia el servidor con nodemon.

16 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Demostración de API

Implementación de NGRX

Implementemos el NGRX paso a paso. Aquí está el diagrama de la


estructura NGRX para la aplicación. Disponemos de acciones,
reductores, efectos, etc.

17 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Angular con NGRX llamando a la API de NodeJS


Si miramos el diagrama anterior, los componentes de la aplicación
angular invoca la tienda NGRX enviando acciones. Si las acciones
tienen efectos secundarios, como llamar a la API, etc., llamará a la
API a través de los efectos. Una vez que recibimos la respuesta de
la API cambiamos el estado de la aplicación a través de los
reductores. Los reductores aquí son funciones puras, lo que
significa que toman el estado actual y dan salida al nuevo estado
sin mutar el estado actual.

Primero, necesitamos definir el estado en la estructura de carpetas


Angular. Normalmente mantengo una carpeta separada para el
estado de la aplicación.

18 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Estado de la aplicación

Flujo de inicio de sesión / registro

Todas las acciones pertenecen al flujo de inicio de sesión y registro


se definen a continuación. Las acciones son los objetos que tienen
tipo y carga útil. La carga útil es opcional aquí. Tenga en cuenta
que createAction y props se importan desde ngrx / store.

import { createAction, props } from '@ngrx/store';

import { User } from '../entity';

export const USER_LOGIN = '[Login Page] Login';

19 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export const USER_LOGIN_SUCCESS = '[Login Page] Login


Success';

export const USER_LOGIN_FAILURE = '[Login Page] Login


Failure';

export const login = createAction(

USER_LOGIN,

props<{user: User}>()

);

export const loginSuccess = createAction(

USER_LOGIN_SUCCESS,

props<any>()

export const loginFailure = createAction(

USER_LOGIN_FAILURE,

props<{message: string}>()

20 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Este es el archivo de acciones para el flujo de registro.

import { createAction, props } from '@ngrx/store';

import { User } from '../entity';

export const USER_SIGNUP = '[SignUp Page] Signup';

export const USER_SIGNUP_SUCCESS = '[SignUp Page]


Signup Success';

export const USER_SIGNUP_FAILURE = '[SignUp Page]


Signup Failure';

export const signup = createAction(

USER_SIGNUP,

props<{user: User}>()

);

export const signupSuccess = createAction(

USER_SIGNUP_SUCCESS,

21 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

props<any>()

export const signupFailure = createAction(

USER_SIGNUP_FAILURE,

props<{message: string}>()

Dado que las acciones de inicio de sesión y registro deben llamar a


la API para autenticar y registrar usuarios. Necesita definir los
efectos que manejan los efectos secundarios.

import { Injectable } from '@angular/core';

import { Actions, createEffect, ofType } from '@ngrx/effects';

import { map, exhaustMap, catchError } from 'rxjs/operators';

import { of } from 'rxjs';

import { AppService } from '../../_services/app.service';

import * as userActions from '../actions';

22 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

@Injectable()

export class UserEffects {

constructor(

private actions$: Actions,

private appService: AppService

) {}

userLogin$ = createEffect(() =>

this.actions$.pipe(

ofType(userActions.login),

exhaustMap(action =>

this.appService.login(action.user).pipe(

map(response => userActions.loginSuccess(response)),

catchError((error: any) => of(userActions.loginFailure(error))))

23 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

);

userSignup$ = createEffect(() =>

this.actions$.pipe(

ofType(userActions.signup),

exhaustMap(action =>

this.appService.signup(action.user).pipe(

map(response => userActions.signupSuccess(response)),

catchError((error: any) => of(userActions.signupFailure(error))))

);

Hemos definido dos funciones en este archivo de efectos. Uno es


para Acción de tipo inicio de sesión y otro es para Acción de tipo
registro. Puede ver que estamos llamando a la API y mapeando la
respuesta a la carga útil de Acciones apropiada.

24 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Aquí está el reductor para el flujo de inicio de sesión y registro del


usuario. Si observa el archivo a continuación, hemos definido el
estado inicial. Para cada acción, cambiamos el estado en
consecuencia. También estamos exportando algunas funciones
que brindan algunos datos que son útiles para los componentes.

import { Action, createReducer, on } from '@ngrx/store';

import { User } from '../entity';

import * as userActions from '../actions';

import * as storage from '../state/storage';

export interface State {

user: User;

result: any;

isLoading: boolean;

isLoadingSuccess: boolean;

isLoadingFailure: boolean;

25 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export const initialState: State = {

user: storage.getItem('user').user,

result: '',

isLoading: false,

isLoadingSuccess: false,

isLoadingFailure: false

};

const loginReducer = createReducer(

initialState,

on(userActions.login, (state, {user}) => ({user, isLoading:


true})),

on(userActions.loginSuccess, (state, result) => ({user:


result.user, result, isLoading: false, isLoadingSuccess: true})),

on(userActions.signup, (state, {user}) => ({user, isLoading:


true})),

on(userActions.signupSuccess, (state, result) => ({user:

26 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

state.user, result, isLoading: false, isLoadingSuccess: true}))

);

export function reducer(state: State | undefined, action: Action):


any {

return loginReducer(state, action);

export const getLoggedInUser = (state: State) => {

return {

user: state.user,

isLoadingSuccess: state.isLoadingSuccess

};

export const userLogin = (state: State) => {

return {

user: state.user,

27 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

result: state.result,

isLoading: state.isLoading,

isLoadingSuccess: state.isLoadingSuccess

};

export const userSignup = (state: State) => {

return {

user: state.user,

result: state.result,

isLoading: state.isLoading,

isLoadingSuccess: state.isLoadingSuccess

};

Flujo de tareas pendientes

28 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Todas las acciones que pertenecen al flujo de Tareas se definen a


continuación. Las acciones son los objetos que tienen tipo y carga
útil. La carga útil es opcional aquí. Tenga en cuenta que
createAction y props se importan desde ngrx / store.

import { createAction, props } from '@ngrx/store';

import { Task } from '../entity';

export const GET_TASKS = '[Task] Get Tasks';

export const GET_TASKS_SUCCESS = '[Task] Get Tasks


Success';

export const GET_TASKS_FAILURE = '[Task] Get Tasks


Failure';

export const CREATE_TASK = '[Task] Create Task';

export const CREATE_TASK_SUCCESS = '[Task] Create Task


Success';

export const CREATE_TASK_FAILURE = '[Task] Create Task


Failure';

29 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export const DELETE_TASK = '[Task] Delete Task';

export const DELETE_TASK_SUCCESS = '[Task] Delete Task


Success';

export const DELETE_TASK_FAILURE = '[Task] Delete Task


Failure';

export const EDIT_TASK = '[Task] Edit Task';

export const EDIT_TASK_SUCCESS = '[Task] Edit Task


Success';

export const EDIT_TASK_FAILURE = '[Task] Edit Task Failure';

export const getTasks = createAction(

GET_TASKS

);

export const getTasksSuccess = createAction(

GET_TASKS_SUCCESS,

props<any>()

30 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

);

export const getTasksFailure = createAction(

GET_TASKS_FAILURE,

props<{any}>()

);

export const createTask = createAction(

CREATE_TASK,

props<{task: any}>()

);

export const createTaskSuccess = createAction(

CREATE_TASK_SUCCESS,

props<any>()

);

export const createTaskFailure = createAction(

31 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

CREATE_TASK_FAILURE,

props<{any}>()

);

export const deleteTask = createAction(

DELETE_TASK,

props<{taskid}>()

);

export const deleteTaskSuccess = createAction(

DELETE_TASK_SUCCESS,

props<any>()

);

export const deleteTaskFailure = createAction(

DELETE_TASK_FAILURE,

props<{any}>()

32 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

);

export const editTask = createAction(

EDIT_TASK,

props<{task: any}>()

);

export const editTaskSuccess = createAction(

EDIT_TASK_SUCCESS,

props<any>()

);

export const editTaskFailure = createAction(

EDIT_TASK_FAILURE,

props<{any}>()

);

Dado que las acciones de todo deben llamar a la API para crear,
eliminar, editar y obtener tareas de la API. Necesita definir los

33 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

efectos que manejan los efectos secundarios.

import { Injectable } from '@angular/core';

import { Actions, createEffect, ofType } from '@ngrx/effects';

import { of } from 'rxjs';

import { map, exhaustMap, catchError } from 'rxjs/operators';

import { TodoService } from '../../_services';

import * as todoActions from '../actions';

@Injectable()

export class TodoEffects {

constructor(

private actions$: Actions,

private todoService: TodoService

) {}

getTasks$ = createEffect(() =>

34 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

this.actions$.pipe(

ofType(todoActions.getTasks),

exhaustMap(action =>

this.todoService.getTasks().pipe(

map(response => {

console.log("response:::", response)

return todoActions.getTasksSuccess({response})

}),

catchError((error: any) =>


of(todoActions.getTasksFailure(error))))

);

createTask$ = createEffect(() =>

this.actions$.pipe(

35 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

ofType(todoActions.createTask),

exhaustMap(action =>

this.todoService.addTask(action.task).pipe(

map(response => todoActions.createTaskSuccess(response)),

catchError((error: any) =>


of(todoActions.createTaskFailure(error))))

);

deleteTask$ = createEffect(() =>

this.actions$.pipe(

ofType(todoActions.deleteTask),

exhaustMap(action =>
this.todoService.deleteTask(action.taskid).pipe(

map(response => todoActions.deleteTaskSuccess(response)),

36 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

catchError((error: any) =>


of(todoActions.deleteTaskFailure(error))))

);

editTask$ = createEffect(() =>

this.actions$.pipe(

ofType(todoActions.editTask),

exhaustMap(action =>

this.todoService.editTask(action.task).pipe(

map(response => todoActions.editTaskSuccess(response)),

catchError((error: any) =>


of(todoActions.editTaskFailure(error))))

37 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

);

Hemos definido cuatro funciones en este archivo de efectos. Uno


para cada operación CRUD. Puede ver que estamos llamando a la
API y mapeando la respuesta a la carga útil de Acciones
apropiada.

Aquí está el reductor para el flujo de todo. Si observa el archivo a


continuación, hemos definido el estado inicial. Para cada acción,
cambiamos el estado en consecuencia. También estamos
exportando algunas funciones que brindan algunos datos que son
útiles para los componentes.

import { Action, createReducer, on } from '@ngrx/store';

import { Task } from '../entity';

import * as todoActions from '../actions';

import * as _ from 'lodash'

import * as storage from '../state/storage';

export interface State {

38 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

tasks?: Task[];

currentTask?: Task;

deleteTaskId?: any;

result?: any;

isLoading?: boolean;

isLoadingSuccess?: boolean;

isLoadingFailure?: boolean;

export const initialState: State = {

tasks: storage.getItem('todo').tasks,

currentTask: {},

deleteTaskId: '',

result: '',

isLoading: false,

isLoadingSuccess: false,

39 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

isLoadingFailure: false

};

const todoReducer = createReducer(

initialState,

// GeTasks

on(todoActions.getTasks, (state) => ({...state, isLoading: true})),

on(todoActions.getTasksSuccess, (state, result) => ({tasks:


result.response, isLoading: false, isLoadingSuccess: true})),

// Create Task Reducers

on(todoActions.createTask, (state, {task}) => ({...state,


isLoading: true, currentTask: task})),

on(todoActions.createTaskSuccess, (state, result) => {

const tasks = undefined !== state.tasks ?


_.cloneDeep(state.tasks) : [];

40 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

const currentTask = undefined !== state.currentTask ?


_.cloneDeep(state.currentTask) : {};

currentTask.id = result.taskId;

tasks.push(currentTask);

return {

tasks,

isLoading: false,

isLoadingSuccess: true

};

}),

// Delete Task Reducers

on(todoActions.deleteTask, (state, {taskid}) => ({...state,


isLoading: true, deleteTaskId: taskid})),

on(todoActions.deleteTaskSuccess, (state, result) => {

let tasks = undefined !== state.tasks ? _.cloneDeep(state.tasks)


: [];

41 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

if (result.status) {

tasks = tasks.filter(task => task.id !== state.deleteTaskId);

return {

tasks,

isLoading: false,

isLoadingSuccess: true

};

}),

// Edit Task Reducers

on(todoActions.editTask, (state, {task}) => ({...state, isLoading:


true, currentTask: task})),

on(todoActions.editTaskSuccess, (state, result) => {

let tasks = undefined !== state.tasks ? _.cloneDeep(state.tasks)


: [];

const currentTask = undefined !== state.currentTask ?

42 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

_.cloneDeep(state.currentTask) : {};

tasks = tasks.map(tsk => {

if (tsk.id === currentTask.id) {

tsk = currentTask;

return tsk;

});

return {

tasks,

isLoading: false,

isLoadingSuccess: true

};

})

);

export function reducer(state: State | undefined, action: Action):

43 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

any {

return todoReducer(state, action);

export const getTasks = (state: State) => {

return {

tasks: state.tasks,

isLoading: state.isLoading,

isLoadingSuccess: state.isLoadingSuccess

};

};

Aquí está el archivo index.ts completo donde define sus reductores


y funciones de exportación con la ayuda de selectores.

import {

ActionReducer,

ActionReducerMap,

44 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

createFeatureSelector,

createSelector,

MetaReducer

} from '@ngrx/store';

import { localStorageSync } from 'ngrx-store-localstorage';

import { environment } from '../../environments/environment';

import * as fromUser from './reducers/user.reducer';

import * as fromTodo from './reducers/todo.reducer';

export interface State {

user: fromUser.State;

todo: fromTodo.State;

export const reducers: ActionReducerMap<State> = {

user: fromUser.reducer,

todo: fromTodo.reducer,

45 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

};

const reducerKeys = ['user', 'todo'];

export function localStorageSyncReducer(reducer:


ActionReducer<any>): ActionReducer<any> {

return localStorageSync({keys: reducerKeys})(reducer);

// console.log all actions

export function debug(reducer: ActionReducer<any>):


ActionReducer<any> {

return function(state, action) {

console.log('state', state);

console.log('action', action);

return reducer(state, action);

};

46 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export const metaReducers: MetaReducer<State>[] =


!environment.production ? [debug, localStorageSyncReducer] :
[localStorageSyncReducer];

export const getLoginState =


createFeatureSelector<fromUser.State>('user');

export const getLoggedInUser = createSelector(

getLoginState,

fromUser.getLoggedInUser

);

export const userLogin = createSelector(

getLoginState,

fromUser.userLogin

);

export const userSignup = createSelector(

getLoginState,

47 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

fromUser.userSignup

);

// Todo reducers Begin

export const geTodoState =


createFeatureSelector<fromTodo.State>('todo');

export const getTasks = createSelector(

geTodoState,

fromTodo.getTasks

);

Implementación angular

Hemos visto implementaciones de API y NGRX. Es hora de ver


cómo podemos integrar la tienda NGRX en la aplicación Angular.
Lo primero que debemos hacer es importar todo el código
relacionado con NGRX en el módulo de la aplicación o el módulo
de funciones como se muestra a continuación.

48 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { FormsModule } from '@angular/forms';

import { HttpClientModule } from '@angular/common/http';

import { BrowserAnimationsModule } from '@angular/platform-


browser/animations';

import { AppRoutingModule } from './app-routing.module';

import { DashboardModule } from './dashboard


/dashboard.module';

import { SharedModule } from './shared/shared.module';

import { LoginModule } from './login/login.module';

import { ModalModule } from 'ngx-bootstrap/modal';

import { AppComponent } from './app.component';

// ngrx related imports

import { StoreModule } from '@ngrx/store';

49 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

import { reducers, metaReducers } from './app-state';

import { UserEffects, TodoEffects } from './app-state/effects';

import { EffectsModule } from '@ngrx/effects';

@NgModule({

declarations: [

AppComponent

],

imports: [

BrowserModule,

AppRoutingModule,

FormsModule,

BrowserAnimationsModule,

HttpClientModule,

DashboardModule,

SharedModule,

50 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

LoginModule,

ModalModule.forRoot(),

// ngrx related imports

StoreModule.forRoot(reducers, {

metaReducers

}),

EffectsModule.forRoot([UserEffects, TodoEffects])

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Como puede ver arriba, necesitamos importar efectos y


deberíamos estar registrados con EffectsModule desde NGRX
Store. Veamos un ejemplo de cómo podemos distribuir las
acciones y escuchar los cambios de la tienda.

51 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

Aquí está el componente de inicio de sesión en el que importamos


la tienda ngrx y las acciones que hemos definido anteriormente.

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Router } from '@angular/router';

import { NgForm } from '@angular/forms';

import { Store } from '@ngrx/store';

import * as userActions from '../app-state/actions';

import * as fromRoot from '../app-state';

import { Subject } from 'rxjs';

import { takeUntil } from 'rxjs/operators';

@Component({

selector: 'app-login',

templateUrl: './login.component.html',

styleUrls: ['./login.component.css']

})

52 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export class LoginComponent implements OnInit, OnDestroy {

constructor(private router: Router, private readonly store: Store)


{

this.store.select(fromRoot.userLogin).pipe(

takeUntil(this.destroy$)

).subscribe(data => {

console.log('data::::', data);

if (data.isLoadingSuccess && data.result.status) {

this.router.navigate(['/dashboard']);

});

model: User = new User();

destroy$: Subject<boolean> = new Subject<boolean>();

ngOnInit() {

53 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

onSubmit(loginForm: NgForm) {

console.log(this.model)

this.store.dispatch(userActions.login({user: { email:
this.model.email, password: this.model.password }}));

ngOnDestroy(){

this.destroy$.next(true);

this.destroy$.unsubscribe();

export class User {

constructor(

){}

54 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

public email: string;

public password: string;

Como en el componente anterior, enviamos acciones con


this.store.dispatch y leemos de la tienda con la ayuda de
selectores como this.store.select.

Aquí están las API que son llamadas por efectos NGRX

import { Injectable } from '@angular/core';

import { Subject, Observable, of } from 'rxjs';

import { HttpClient, HttpHeaders } from '@angular/common


/http';

import { map, catchError } from 'rxjs/operators';

@Injectable({

providedIn: 'root'

})

55 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

export class AppService {

private userLoggedIn = new Subject<boolean>();

loginUrl = '/api/login';

signupUrl = '/api/signup';

constructor(private http: HttpClient) {

this.userLoggedIn.next(false);

setUserLoggedIn(userLoggedIn: boolean) {

this.userLoggedIn.next(userLoggedIn);

getUserLoggedIn(): Observable<boolean> {

return this.userLoggedIn.asObservable();

login(user: any) {

56 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

const headers = new HttpHeaders({'Content-Type' :


'application/json'});

const options = {headers};

return this.http.post(this.loginUrl, {user}, options).pipe(

map((response: Response) => response),

catchError(err => {

console.log(err);

return of([]);

})

);

signup(user: any) {

const headers = new HttpHeaders({'Content-Type' :


'application/json'});

const options = {headers};

57 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

return this.http.post(this.signupUrl, {user}, options).pipe(

map((response: Response) => response),

catchError(err => {

console.log(err);

return of([]);

})

);

import { Injectable } from '@angular/core';

import { HttpClient } from '@angular/common/http';

@Injectable({

providedIn: 'root'

})

export class TodoService {

58 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

constructor(private http: HttpClient) { }

rootURL = '/api';

getTasks() {

return this.http.get(this.rootURL + '/tasks');

addTask(task: any) {

return this.http.post(this.rootURL + '/task', {task});

editTask(task: any) {

return this.http.put(this.rootURL + '/task', {task});

deleteTask(taskId: any) {

console.log('deleting task:::', taskId);

59 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

return this.http.delete(`${this.rootURL}/task/${taskId}`);

Puede consultar el resto del ejemplo en el enlace de Github


proporcionado anteriormente.

Resumen

NGRX es una herramienta de gestión de estado inspirada en redux


para las aplicaciones angulares.

Cuando su aplicación se hace cada vez más grande, la


comunicación se vuelve difícil de manejar. NGRX proporciona un
flujo de datos unidireccional y una única fuente de información para
toda la aplicación.

Los componentes que conocen la tienda se denominan


componentes inteligentes y los componentes que no conocen la
tienda se denominan componentes tontos.

A veces tenemos que hacer llamadas a la API para obtener los


datos de la aplicación. Siempre que la tienda necesita datos de la
API de backend, utiliza efectos NGRX para realizar una llamada a

60 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

la API y recuperar los datos y actualizar la tienda.

Las acciones se envían desde los componentes y servicios. Estos


son solo eventos únicos con tipo y carga útil y se pueden enviar a
la tienda

Los reductores son las funciones puras que toman la última


acción y el estado actual y devuelven el nuevo estado.

Los selectores son las funciones puras que nos permiten


seleccionar una porción del estado.

El Estado se puede acceder a través de tienda observables en


componentes y servicios

Los efectos NGRX son las funciones que se pueden ejecutar para
obtener los nuevos datos para el estado. Por ejemplo, si su
componente necesita nuevos datos de la API, el componente envía
una acción, los reductores invocan los efectos y servicios para
obtener los nuevos datos, el reductor devuelve el nuevo estado con
esos datos de la API.

NGRX no es para pequeñas aplicaciones angulares ya que hay


mucho código repetitivo. También se necesita mucha curva de
aprendizaje para implementar la tienda NGRX en cualquier

61 of 62 7/25/21, 13:49
Cómo implementar la tienda NGRX en aplicaciones angulares about:reader?url=https://ichi.pro/es/como-implementar-la-tienda-ngrx-en-aplica...

aplicación Angular. Por lo tanto, elija sabiamente.

62 of 62 7/25/21, 13:49

También podría gustarte