Le applicazioni angolari non hanno alcun modo rapido per ottenere la persistenza dei dati. Di conseguenza, l’esperienza nello sviluppo di applicazioni di grandi dimensioni che richiedono molta comunicazione di dati tra i componenti può essere molto frenetica. La gestione dello stato è forse la parte più difficile da gestire in qualsiasi applicazione su larga scala.
In questo articolo parleremo di Pacchetto NgRx e come viene utilizzato per la gestione dello stato e la comunicazione dei dati in un’applicazione Angular. NgRx è costituito da molte librerie che aiutano gli sviluppatori a gestire lo stato in un’applicazione Angular lato client moderna e su larga scala.
Gestione dello stato delle applicazioni front-end
Nelle applicazioni di backend, possiamo utilizzare i database per la gestione dello stato. Tuttavia, nel caso delle applicazioni front-end, abbiamo anche bisogno di un meccanismo per archiviare i dati. Questi dati possono essere qualcosa come una risposta ricevuta da un server, dati di input del modulo o qualcos’altro.
L’idea della gestione dello stato reattivo è di memorizzare tutto lo stato dell’applicazione in un archivio centrale per la comunicazione dei dati. Quindi, nel contesto della gestione statale, abbiamo il nostro stato, che sarebbe responsabile della rappresentazione dell’applicazione che risiede effettivamente nel negozio.
Cos’è NgRx?
NgRx è un gruppo di librerie che forniscono la gestione dello stato reattivo in un’applicazione. Un buon sistema di gestione dello stato dovrebbe consentire di fornire una rappresentazione dello stato, aggiornare o modificare il suo valore, tenere traccia dello stato quando il valore cambia e, infine, recuperare lo stato. Ispirato al modello Redux, NgRx fornisce un modo per semplificare facilmente lo stato dell’applicazione ed eseguire il flusso di dati unidirezionale nell’applicazione. Il pacchetto NgRx è composto dalle seguenti librerie:
- Negozio
- Effetti
- Entità
- RouterStore
- ComponentStore
Leggi: Lavorare con Redux per la gestione dello stato
NgRx e Redux
NgRx utilizza il modello Redux. Si compone principalmente di tre modelli:
Negozio: Un punto centrale che contiene tutti gli stati di un’applicazione
Azione: Gli eventi univoci che descrivono i cambiamenti nello stato di un’applicazione
Riduttore: Le funzioni utilizzate per eseguire le transizioni di stato legando il negozio e le azioni insieme
Elementi fondamentali di NgRx
In questa sezione vedremo come gli elementi di NgRx, come store, action e reducer, vengono utilizzati per semplificare il processo di gestione dello stato nelle applicazioni Angular.
NgRx Store
Il negozio svolge un ruolo fondamentale nella gestione dello stato. Store contiene i dati che utilizzeremmo nella nostra app.
Ecco un esempio di un negozio in NgRX:
const state = { persons: [ { name: "Adam", age: 45 }, { name: "George", age: 65 } ], bookDescription: { name: "Name of Book", author: "Kate Chopin" } }
Azioni NgRx
Le azioni NgRx sono i metodi inviati dal componente o dal servizio quando viene chiamato un evento. Ecco un esempio di un’azione NgRx:
const NameModifyAction = { type: "Name Modify", name: "Kate" }
È possibile definire il tipo e il carico utile in azione metodo.
Riduttori NgRx
I riduttori NgRx sono le funzioni che gestiscono le transizioni di stato. Riceve lo stato corrente e un’azione come argomenti e restituisce un nuovo stato. Per comprendere meglio i riduttori, considerare il codice seguente:
const _reducer = createReducer( initialState, on(nameOfAction, (state, action) => { return { ...state, someState: action.anyState } }) )
Qui, createReducer la funzione è responsabile della gestione delle transizioni di stato. Abbiamo anche importato lo stato iniziale nel nostro file reducer per accedere allo stato corrente. Dopo di che, il in poi viene utilizzato l’evento, che accetta il nome dell’azione come parametro e viene utilizzato per attivare l’azione.
Leggi: Come ottimizzare le applicazioni angolari
Costruire una semplice app angolare usando NgRx
Crea una nuova app Angular eseguendo il seguente comando sul tuo terminale:
ng new country-list
Quindi, installa lo store NgRx nel tuo progetto:
npm install @ngrx/store –-save
Ora apri l’applicazione in VSCode (o qualsiasi editor di codice o IDE che ti piace usare) e crea una nuova cartella chiamata negozio dentro il src/app directory.
All’interno della directory del negozio, crea una cartella dei modelli e definisci un’interfaccia lì per lista-paese:
export interface CountryItem { id: string; name: string; shortName: string; }
Quindi, crea un Azione directory all’interno del negozio cartella. Qui è dove definiremo tutte le azioni NgRx. Quindi crea un country.action.ts file all’interno della directory delle azioni e aggiungere il seguente codice ad esso:
import { Action } from '@ngrx/store'; import { CountryItem } from '../models/countryItem.model'; export enum CountryActionType { ADD_ITEM = '[COUNTRY] Add Country', } export class AddItemAction implements Action { readonly type = CountryActionType.ADD_ITEM; //optional payload constructor(public payload: CountryItem) {} } export type CountryAction = AddItemAction;
Nel passaggio successivo, creeremo a riduttori directory all’interno del negozio directory. Nel riduttori directory, creeremo a paese.riduttore.ts file e aggiungere il seguente codice ad esso:
import { CountryItem } from '../models/countryItem.model'; import { CountryAction, CountryActionType } from '../actions/country.action'; // //create a dummy initial state const initialState: Array = [ { id: '1', name: 'United States of America', shortName: 'US', }, ]; export function CountryReducer( state: Array = initialState, action: CountryAction ) { switch (action.type) { case CountryActionType.ADD_ITEM: return [...state, action.payload]; default: return state; } }
Ricordiamo che l’obiettivo di qualsiasi sistema di gestione statale è quello di mantenere tutto lo stato di un’applicazione in un unico negozio in modo che sia facilmente accessibile da qualsiasi parte dell’applicazione. Ora creeremo un file chiamato state.model.ts all’interno della directory del modello e creare un Stato dell’app interfaccia utilizzando il seguente codice:
import { CountryItem } from './countryItem.model'; export interface AppState { readonly country: Array; }
Ora, dobbiamo registrare NgRx nel nostro file del modulo principale app.modules.ts:
import { CountryReducer } from './store/reducers/country.reducer'; import { FormsModule } from '@angular/forms';
Successivamente, registreremo i moduli importati nell’array imports:
imports: [ FormsModule, StoreModule.forRoot({ country: CountryReducer, }), ]
NgRx è ora pronto per l’uso nei nostri componenti. Quindi modifichiamo il nostro file del componente principale app.component.ts in modo che possiamo usare NgRx lì:
import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { CountryItem } from './store/models/countryItem.model'; import { AppState } from './store/models/app-state.model'; import { NgForm } from '@angular/forms'; import { AddItemAction } from './store/actions/country.action'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { countryItems$: Observable<Array>; constructor(private store: Store) {} ngOnInit(): void { this.countryItems$ = this.store.select((store) => store.country); } }
Qui abbiamo definito il paeseArticolo interfaccia, portato in un osservabile RxJS e lo stato della nostra app. Abbiamo anche impostato paeseArticolo$ a un tipo di osservabile, che è di tipo Vettore, e, infine, impostare il valore di paeseArticolo$ osservabile allo stato restituito. Useremo queste informazioni nel nostro file modello app.component.html:
<div class="col-md-6 py-4"> <ul class="list-group"> <li class="list-group-item" *ngFor="let country of countryItems$ | async"> {{country.name}}: <b>{{country.shortName}}</b> </li> </ul> </div>
Nel passaggio successivo, creeremo un modulo utente per l’aggiunta di paesi all’elenco dei paesi. In questo progetto, utilizziamo Bootstrap per una piacevole esperienza utente:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Angular State Management Demonstration</title> <base href="https://www.htmlgoodies.com/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="https://www.htmlgoodies.com/javascript/angular-state-management-with-ngrx/favicon.ico"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> </head> <body> <app-root></app-root> </body> </html>
Per portare Bootstrap nel nostro progetto, abbiamo aggiunto Bootstrap CSS CDN a file app/index.html.
Nel passaggio successivo, dobbiamo modificare il app.component.html file di conseguenza in modo che l’utente possa aggiungere il nome del paese e il nome breve all’elenco dei paesi.
<section> <div class="container"> <div class="row"> <div class="col-md-6 px-4"> <h4>Angular State Management using NgRx</h4> </div> </div> <div class="row"> <div class="col-md-6 py-4"> <div class="card p-4 shadow-sm"> <form #myform="ngForm" (ngSubmit)="addCountry(myform)"> <div class="form-group"> <label for="name">Identity</label> <input type="text" class="form-control" ngModel name="id" id="id" aria-describedby="name" required> </div> <div class="form-group"> <label for="name">Country Name</label> <input type="text" class="form-control" ngModel name="name" id="name" aria-describedby="name" required> </div> <div class="form-group"> <label for="department">Short Name</label> <input type="text" class="form-control" ngModel name="shortName" id="shortName" required> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> </div> <div class="col-md-6 py-4"> <ul class="list-group"> <li class="list-group-item" *ngFor="let country of countryItems$ | async"> {{country.name}}: <b>{{country.shortName}}</b> </li> </ul> </div> </div> </div> </section>
Successivamente, dobbiamo importare NgForm nel nostro app.component.ts file e creare un metodo per inviare il AggiungiAzioneOggetto:
export class AppComponent implements OnInit { countryItems$: Observable<Array>; constructor(private store: Store) {} ... addCountry(form: NgForm) { this.store.dispatch(new AddItemAction(form.value)); form.reset(); } }
Ecco uno screenshot del risultato finale:
Puoi trovare il codice sorgente da questo articolo su Github.