Avui aprendrem a introduir l’ús de la gestió de l’estat de REDUX en una aplicació web angular amb la biblioteca NGRX
L’equivalent REDUX per a Angular és NGRX .
També us pot interessar: “Unimedia nomenat com a líders tecnològics per Clutch”
A més, el nostre equip de desenvolupadors són experts en la creació de software personalitzat segons els requisits del projecte.
Veurem cada bloc de construcció de NGRX pas a pas
Botiga
El magatzem és un contenidor d’estat controlat dissenyat per ajudar a escriure aplicacions de rendiment i escalables a sobre d’Angular.
Efectes
Els efectes utilitzen fluxos per proporcionar noves fonts d’accions. Per modificar l’estat en funció d’interaccions externes, com ara sol·licituds de xarxa, missatges de connexió web i esdeveniments basats en el temps. Per tant, són el mètode preferit per obtenir dades i mantenir part de la lògica de l’aplicació.
Selectors
Els Selectors són funcions pures utilitzades per obtenir porcions de l’estat de la botiga. Així, seleccionen peces d’informació de la botiga que seran consumides per altres parts de la lògica de l’aplicació.
Reductors
Els reductors de NgRx són els responsables de gestionar les transicions d’un estat al següent a la vostra aplicació. Les funcions reductores gestionen aquestes transicions determinant quines accions s’han de gestionar en funció del tipus d’acció. En altres paraules, reben accions amb una càrrega útil de dades i canvien l’estat emmagatzemant les dades noves com es desitgi.
Després d’entendre els blocs bàsics de la gestió de l’estat NGRX, ara construirem una aplicació de xat petita d’exemple amb la gestió de l’estat NGRX.
Des de llavors, ja hem creat una aplicació de xat anteriorment a una publicació anterior aquí . Com a resultat, introduirem la gestió de l’estat NGRX per actualitzar la interfície d’usuari mentre s’envia/recep el missatge.
1. Configurar el projecte
/** Clone Repo */
git clone https://github.com/unimedia-technology/amplify-chat-angular.git
/** Enter into project directory */
cd amplify-chat-angular
/** Install the dependencies */
npm i
/** Create a new git branch */
git checkout ngrx
2. Instal·lar les dependències NGRX
ng add @ngrx/store @ngrx/effects @ngrx/component
3. Crear accions
Aquí, crearem 4 accions que són necessàries per gestionar l’estat de l’aplicació de xat.
Fitxer : store/actions/actions.ts
import { createAction, props } from '@ngrx/store';
export const loadMessages = createAction('[Chat] Load Messages', props<{ channelId: string }>());
export const loadMessagesSuccess = createAction('[Chat] Load Messages Success', props<{ messages: any[] }>());
export const sendMessage = createAction('[Chat] Send Message', props<{ message }>());
export const addMessageToList = createAction('[Chat] Add Message To List', props<{ message }>());
4. Crear efectes
Els efectes ofereixen una manera d’interactuar amb aquests serveis i aïllar-los dels components.
Ús
Els efectes són útils, si voleu gestionar tasques com ara obtenir dades, tasques de llarga durada que produeixen diversos esdeveniments i altres interaccions externes.
Nota: per recordar, en la majoria dels escenaris, enviarà accions, però no és obligatori enviar sempre accions.
Per escriure efectes sense enviar les accions, passeu el segon paràmetre acreateEffect()
funcions amb { dispatch: false }
Fitxer: state/effects/effects.ts
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, switchMap } from 'rxjs/operators';
import * as chatActions from '../actions/actions';
import { from } from 'rxjs';
import { APIService } from '../../API.service';
@Injectable()
export class ChatEffects {
constructor(
private actions$: Actions,
private api: APIService,
) { }
/** Load the List of Messages */
loadMessages$ = createEffect(() => this.actions$.pipe(
ofType(chatActions.loadMessages),
switchMap(({ channelId }) => {
return from(this.api.MessagesByChannelId(channelId)).pipe(
map((res: any) => {
return chatActions.loadMessagesSuccess({ messages: res.items });
}),
);
})
));
/** Send message and call no actions */
sendMessage$ = createEffect(() => this.actions$.pipe(
ofType(chatActions.sendMessage),
switchMap(({ message }) => {
return from(this.api.CreateMessage(message));
})
), { dispatch: false });
}
5. Crear reductors
Cada funció de reducció pren el més recentAction
enviat, l’estat actual i determina si es retorna un estat recent modificat o l’estat original. Ara, en l’exemple següent us guiarem sobre com escriure funcions reductores, registreu-les al vostreStore
, i compondre estats de característiques.
Fitxer: store/reducers/reducers.ts
import { Action, createReducer, on } from '@ngrx/store';
import * as chatActions from '../actions/actions';
export interface IChatState {
messages: any[];
}
/** Initial State */
export const initialState: IChatState = {
messages: [],
};
export function chatReducer(state: IChatState | undefined, action: Action): IChatState {
return reducer(state, action);
}
const reducer = createReducer<IChatState>(
initialState,
/** Loaded Messafes */
on(chatActions.loadMessagesSuccess, (state, { messages }) => ({
...state,
messages
})),
/** Add message to the messages array */
on(chatActions.addMessageToList, (state, { message }) => ({
...state,
messages: [...state.messages, message]
})),
);
6. Crear selectors
El selector que hem creat aquí retornarà l’ observable de tots els missatges
Fitxer: store/selectors/selectors.ts
import { createSelector } from '@ngrx/store';
export const selectChatState = (state) => state;
export const selectMessages = createSelector(
selectChatState,
(state) => state.chat.messages
);
7. Gestionar l’Estat
En aquesta secció, veurem quins són tots els esdeveniments on hem d’actualitzar l’estat:
- Carregar l’aplicació
- Enviament d’un missatge
- Recepció d’un missatge
Fitxer: app.component.ts
import { Component, OnInit } from '@angular/core';
import { NavigationEnd, Router, RouterEvent } from '@angular/router';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { delay } from 'rxjs/operators';
import { APIService } from './API.service';
import { addMessageToList, loadMessages, sendMessage } from './store/actions/actions';
import { IChatState } from './store/reducers/reducer';
import { selectMessages } from './store/selectors/selectors';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
title = 'amplify-chat-angular';
username: string;
messages: Observable<any[]>;
constructor(
private api: APIService,
private router: Router,
private store: Store<IChatState>
) { }
ngOnInit(): void {
this.router.events.subscribe((events: RouterEvent) => {
if (events instanceof NavigationEnd) {
const qParams = this.router.routerState.snapshot.root.queryParams;
if (qParams && qParams.user) {
this.username = qParams.user;
} else {
this.router.navigate(['/'], { queryParams: { user: 'Dave' } });
}
}
});
this.listMessages();
this.onCreateMessage();
}
send(event, inputElement: HTMLInputElement): void {
event.preventDefault();
event.stopPropagation();
const input = {
channelID: '2',
author: this.username.trim(),
body: inputElement.value.trim()
};
this.store.dispatch(sendMessage({ message: input }));
inputElement.value = '';
}
listMessages(): void {
this.store.dispatch(loadMessages({ channelId: '2' }));
this.messages = this.store.pipe(
select(selectMessages),
delay(10)
);
}
onCreateMessage(): void {
this.api.OnCreateMessageListener.subscribe(
{
next: (val: any) => {
console.log(val);
this.store.dispatch(addMessageToList({ message: val.value.data.onCreateMessage }));
}
}
);
}
}
Explicació
listMessages
enviaments de mètodesloadMessages
acció ambchannelId
per recollir tots els missatges.- Quan l’usuari envia un missatge,
sendMessage
es crida l’acció i envia el missatge. - Quan l’usuari rep un missatge,
addMessageToList
s’envia l’acció i afegeix el missatgemessages
llista
8. Crea una plantilla
En aquesta secció, farem servir,ngrxPush
tub de@ngrx/component
.
ElngrxPush
la canonada serveix com a reemplaçament d’entrada de laasync
canonada.
ngrxPush
conté un maneig intel·ligent de la detecció de canvis que ens permetrà executar-nos en mode de zona plena i sense cap canvi al codi.
Ús:
ElngrxPush
la canonada es proporciona a través delReactiveComponentModule
. Per tant, per utilitzar-lo afegiu el ReactiveComponentModule
fins alimports
del vostre NgModule .
Fitxer : app.component.html
<div id="root">
<div class="container">
<div class="messages">
<div class="messages-scroller">
<ng-container *ngIf="messages$ | async as messages">
<ng-container *ngFor="let message of messages">
<div [ngClass]="message.author === username ? 'message me' : 'message'">
{{message.body}}
</div>
</ng-container>
</ng-container>
</div>
</div>
<div class="chat-bar">
<div class="form">
<input #messageInput type="text" name="messageBody" placeholder="Type your message here" value="
(keyup.enter)="send($event, messageInput)" />
</div>
</div>
</div>
</div>
Això és tot, ara estem gestionant l’estat mitjançant NGRX.
T’ha agradat llegir això i t’agradaria aprendre més sobre angular i redux?, aquí hi ha un altre gran article, fes-hi una ullada!
Unimedia Technology
Aquí a Unimedia Technology tenim un equip de desenvolupadors angulars que poden desenvolupar els vostres taulers web i aplicacions web més difícils.