使用Firebase在Angular中进行状态管理

本文概述

  • Angular中的组件, 服务, Firestore和状态管理
  • Angular / Firebase示例应用程序
  • Firestore和商店基类
  • 放在一起
  • 创建视图组件
  • 员工表格
  • 使用Observables管理Angular应用程序状态…检查!
状态管理是开发Web应用程序时要考虑的非常重要的体系结构。
在本教程中, 我们将介绍一种简单的方法来管理以Firebase为后端的Angular应用程序中的状态。
我们将介绍一些概念, 例如州, 商店和服务。希望这将帮助你更好地理解这些术语, 并更好地理解其他状态管理库, 例如NgRx和NgXs。
我们将建立一个员工管理页面, 以涵盖一些不同的状态管理方案以及可以解决这些方案的方法。
Angular中的组件, 服务, Firestore和状态管理 在典型的Angular应用程序中, 我们具有组件和服务。通常, 组件将用作视图模板。服务将包含业务逻辑和/或与外部API或其他服务进行通信以完成操作或检索数据。
使用Firebase在Angular中进行状态管理

文章图片
组件通常会显示数据, 并允许用户与应用交互以执行操作。在执行此操作时, 数据可能会更改, 并且应用程序会通过更新视图来反映这些更改。
Angular的更改检测引擎负责检查绑定到视图的组件中的值何时发生更改, 并相应地更新视图。
随着应用的发展, 我们将开始拥有越来越多的组件和服务。通常, 了解数据如何变化并跟踪发生的位置可能很棘手。
Angular和Firebase
当我们使用Firebase作为后端时, 我们将获得一个真正简洁的API, 其中包含构建实时应用程序所需的大多数操作和功能。
@ angular / fire是官方的Angular Firebase库。该层位于Firebase JavaScript SDK库的顶层, 可简化Angular应用中Firebase SDK的使用。它非常适合Angular的良好做法, 例如使用Observables从Firebase获取和显示数据到我们的组件。
使用Firebase在Angular中进行状态管理

文章图片
商店和州
我们可以将” 状态” 视为在应用程序中任何给定时间点显示的值。商店只是该应用程序状态的持有者。
可以将状态建模为单个普通对象或一系列对象, 以反映应用程序的值。
使用Firebase在Angular中进行状态管理

文章图片
Angular / Firebase示例应用程序 让我们对其进行构建:首先, 我们将使用Angular CLI创建一个基本的应用程序支架, 并将其与Firebase项目连接。
$ npm install -g @angular/cli $ ng new employees-admin`Would you like to add Angular routing? Yes Which stylesheet format would you like to use? SCSS$ cd employees-admin/ $ npm install bootstrap # We'll add Bootstrap for the UI

并且, 在styles.scss上:
// ... @import "~bootstrap/scss/bootstrap";

接下来, 我们将安装@ angular / fire:
npm install firebase @angular/fire

现在, 我们将在Firebase控制台上创建一个Firebase项目。
使用Firebase在Angular中进行状态管理

文章图片
然后, 我们准备创建Firestore数据库。
在本教程中, 我将从测试模式开始。如果你打算发布产品, 则应执行规则以禁止不当访问。
使用Firebase在Angular中进行状态管理

文章图片
转到项目概述→项目设置, 然后将Firebase Web配置复制到本地环境/environment.ts。
使用Firebase在Angular中进行状态管理

文章图片
export const environment = { production: false, firebase: { apiKey: "< api-key> ", authDomain: "< auth-domain> ", databaseURL: "< database-url> ", projectId: "< project-id> ", storageBucket: "< storage-bucket> ", messagingSenderId: "< messaging-sender-id> " } };

至此, 我们已经为我们的应用准备了基本的支架。如果我们提供服务, 我们将获得:
使用Firebase在Angular中进行状态管理

文章图片
Firestore和商店基类 我们将创建两个通用抽象类, 然后将其键入并扩展以构建我们的服务。
泛型允许你编写没有绑定类型的行为。这为你的代码增加了可重用性和灵活性。
通用Firestore服务
为了利用TypeScript泛型, 我们要做的是为@ angular / fire firestore服务创建一个基本的泛型包装。
让我们创建app / core / services / firestore.service.ts。
这是代码:
import { Inject } from "@angular/core"; import { AngularFirestore, QueryFn } from "@angular/fire/firestore"; import { Observable } from "rxjs"; import { tap } from "rxjs/operators"; import { environment } from "src/environments/environment"; export abstract class FirestoreService< T> {protected abstract basePath: string; constructor( @Inject(AngularFirestore) protected firestore: AngularFirestore, ) {}doc$(id: string): Observable< T> { return this.firestore.doc< T> (`${this.basePath}/${id}`).valueChanges().pipe( tap(r => { if (!environment.production) { console.groupCollapsed(`Firestore Streaming [${this.basePath}] [doc$] ${id}`) console.log(r) console.groupEnd() } }), ); }collection$(queryFn?: QueryFn): Observable< T[]> { return this.firestore.collection< T> (`${this.basePath}`, queryFn).valueChanges().pipe( tap(r => { if (!environment.production) { console.groupCollapsed(`Firestore Streaming [${this.basePath}] [collection$]`) console.table(r) console.groupEnd() } }), ); }create(value: T) { const id = this.firestore.createId(); return this.collection.doc(id).set(Object.assign({}, { id }, value)).then(_ => { if (!environment.production) { console.groupCollapsed(`Firestore Service [${this.basePath}] [create]`) console.log('[Id]', id, value) console.groupEnd() } }) }delete(id: string) { return this.collection.doc(id).delete().then(_ => { if (!environment.production) { console.groupCollapsed(`Firestore Service [${this.basePath}] [delete]`) console.log('[Id]', id) console.groupEnd() } }) }private get collection() { return this.firestore.collection(`${this.basePath}`); } }

此抽象类将用作Firestore服务的通用包装。
这应该是我们唯一应注入AngularFirestore的地方。当@ angular / fire库更新时, 这将使影响最小化。此外, 如果在某个时候我们想更改库, 则只需要更新此类。
我添加了doc $, collection $, create和delete。它们包装@ angular / fire的方法, 并在Firebase流数据时提供日志记录-这对于调试非常方便-在创建或删除对象之后。
通用商店服务
我们的通用商店服务将使用RxJS的BehaviorSubject构建。 BehaviorSubject允许订户在订阅后立即获得最后发出的值。对于我们来说, 这很有用, 因为当我们的所有组件订阅商店时, 我们都可以使用初始值开始商店。
商店将有两种方法, 补丁和设置。 (我们稍后将创建get方法。)
让我们创建app / core / services / store.service.ts:
import { BehaviorSubject, Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; export abstract class StoreService< T> {protected bs: BehaviorSubject< T> ; state$: Observable< T> ; state: T; previous: T; protected abstract store: string; constructor(initialValue: Partial< T> ) { this.bs = new BehaviorSubject< T> (initialValue as T); this.state$ = this.bs.asObservable(); this.state = initialValue as T; this.state$.subscribe(s => { this.state = s }) }patch(newValue: Partial< T> , event: string = "Not specified") { this.previous = this.state const newState = Object.assign({}, this.state, newValue); if (!environment.production) { console.groupCollapsed(`[${this.store} store] [patch] [event: ${event}]`) console.log("change", newValue) console.log("prev", this.previous) console.log("next", newState) console.groupEnd() } this.bs.next(newState) }set(newValue: Partial< T> , event: string = "Not specified") { this.previous = this.state const newState = Object.assign({}, newValue) as T; if (!environment.production) { console.groupCollapsed(`[${this.store} store] [set] [event: ${event}]`) console.log("change", newValue) console.log("prev", this.previous) console.log("next", newState) console.groupEnd() } this.bs.next(newState) } }

作为通用类, 我们将推迟键入, 直到适当扩展为止。
构造函数将接收Partial < T> 类型的初始值。这将允许我们仅将值应用于状态的某些属性。构造函数还将订阅内部BehaviorSubject发射, 并在每次更改后使内部状态保持更新。
patch()将接收Partial < T> 类型的newValue并将其与商店的当前this.state值合并。最后, 我们next()newState并将新状态发送给所有商店订户。
set()的工作原理非常相似, 只是它不会修补状态值, 而是将其设置为收到的newValue。
更改发生时, 我们将记录状态的上一个和下一个值, 这将有助于我们调试并轻松跟踪状态更改。
放在一起 好吧, 让我们看看这一切在起作用。我们要做的是创建一个雇员页面, 其中将包含一个雇员列表以及一个添加新雇员的表单。
让我们更新app.component.html以添加一个简单的导航栏:
< nav class="navbar navbar-expand-lg navbar-light bg-light mb-3"> < span class="navbar-brand mb-0 h1"> Angular + Firebase + State Management< /span> < ul class="navbar-nav mr-auto"> < li class="nav-item" [routerLink]="['/employees']" routerLinkActive="active"> < a class="nav-link"> Employees< /a> < /li> < /ul> < /nav> < router-outlet> < /router-outlet>

接下来, 我们将创建一个核心模块:
ng g m Core

在core / core.module.ts中, 我们将添加应用所需的模块:
// ... import { AngularFireModule } from '@angular/fire' import { AngularFirestoreModule } from '@angular/fire/firestore' import { environment } from 'src/environments/environment'; import { ReactiveFormsModule } from '@angular/forms'@NgModule({ // ... imports: [ // ... AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule, ReactiveFormsModule, ], exports: [ CommonModule, AngularFireModule, AngularFirestoreModule, ReactiveFormsModule ] }) export class CoreModule { }

【使用Firebase在Angular中进行状态管理】现在, 从” 雇员” 模块开始创建” 雇员” 页面:
ng g m Employees --routing

在employee-routing.module.ts中, 添加员工路线:
// ... import { EmployeesPageComponent } from './components/employees-page/employees-page.component'; // ... const routes: Routes = [ { path: 'employees', component: EmployeesPageComponent } ]; // ...

然后在employee.module.ts中, 导入ReactiveFormsModule:
// ... import { ReactiveFormsModule } from '@angular/forms'; // ...@NgModule({ // ... imports: [ // ... ReactiveFormsModule ] }) export class EmployeesModule { }

现在, 让我们在app.module.ts文件中添加这两个模块:
// ... import { EmployeesModule } from './employees/employees.module'; import { CoreModule } from './core/core.module'; imports: [ // ... CoreModule, EmployeesModule ],

最后, 让我们创建员工页面的实际组件, 以及相应的模型, 服务, 存储和状态。
ng g c employees/components/EmployeesPage ng g c employees/components/EmployeesList ng g c employees/components/EmployeesForm

对于我们的模型, 我们需要一个名为models / employee.ts的文件:
export interface Employee { id: string; name: string; location: string; hasDriverLicense: boolean; }

我们的服务将保存在名为employee / services / employee.firestore.ts的文件中。此服务将扩展之前创建的通用FirestoreService < T> , 我们将仅设置Firestore集合的basePath:
import { Injectable } from '@angular/core'; import { FirestoreService } from 'src/app/core/services/firestore.service'; import { Employee } from '../models/employee'; @Injectable({ providedIn: 'root' }) export class EmployeeFirestore extends FirestoreService< Employee> {protected basePath: string = 'employees'; }

然后, 我们将创建文件employee / states / employees-page.ts。这将用作雇员页面的状态:
import { Employee } from '../models/employee'; export interface EmployeesPage {loading: boolean; employees: Employee[]; formStatus: string; }

该状态将具有一个加载值, 该值确定是否在页面上显示加载消息, 员工本身以及一个用于处理表单状态(例如保存或已保存)的formStatus变量。
我们需要一个位于employee / services / employees-page.store.ts的文件。在这里, 我们将扩展之前创建的StoreService < T> 。我们将设置商店名称, 该名称将在调试时用于标识。
该服务将初始化并保留员工页面的状态。请注意, 构造函数使用页面的初始状态调用super()。在这种情况下, 我们将使用loading = true和一组空员工来初始化状态。
import { EmployeesPage } from '../states/employees-page'; import { StoreService } from 'src/app/core/services/store.service'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class EmployeesPageStore extends StoreService< EmployeesPage> { protected store: string = 'employees-page'; constructor() { super({ loading: true, employees: [], }) } }

现在, 我们创建EmployeesService来集成EmployeeFirestore和EmployeesPageStore:
ng g s employees/services/Employees

请注意, 我们正在此服务中注入EmployeeFirestore和EmployeesPageStore。这意味着EmployeesService将包含并协调对Firestore和商店的调用以更新状态。这将帮助我们为组件调用创建单个API。
import { EmployeesPageStore } from './employees-page.store'; import { EmployeeFirestore } from './employee.firestore'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { Employee } from '../models/employee'; import { tap, map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class EmployeesService {constructor( private firestore: EmployeeFirestore, private store: EmployeesPageStore ) { this.firestore.collection$().pipe( tap(employees => { this.store.patch({ loading: false, employees, }, `employees collection subscription`) }) ).subscribe() }get employees$(): Observable< Employee[]> { return this.store.state$.pipe(map(state => state.loading ? [] : state.employees)) }get loading$(): Observable< boolean> { return this.store.state$.pipe(map(state => state.loading)) }get noResults$(): Observable< boolean> { return this.store.state$.pipe( map(state => { return !state.loading & & state.employees & & state.employees.length === 0 }) ) }get formStatus$(): Observable< string> { return this.store.state$.pipe(map(state => state.formStatus)) }create(employee: Employee) { this.store.patch({ loading: true, employees: [], formStatus: 'Saving...' }, "employee create") return this.firestore.create(employee).then(_ => { this.store.patch({ formStatus: 'Saved!' }, "employee create SUCCESS") setTimeout(() => this.store.patch({ formStatus: '' }, "employee create timeout reset formStatus"), 2000) }).catch(err => { this.store.patch({ loading: false, formStatus: 'An error ocurred' }, "employee create ERROR") }) }delete(id: string): any { this.store.patch({ loading: true, employees: [] }, "employee delete") return this.firestore.delete(id).catch(err => { this.store.patch({ loading: false, formStatus: 'An error ocurred' }, "employee delete ERROR") }) } }

让我们看一下该服务的工作方式。
在构造函数中, 我们将订阅Firestore员工集合。 Firestore从集合中发出数据后, 我们将立即更新商店, 将loading = false设置为Firestore返回的集合并将其设置为员工。由于我们已注入EmployeeFirestore, 因此将从Firestore返回的对象键入Employee, 这将启用更多IntelliSense功能。
当应用程序处于活动状态时, 此订阅将一直有效, 每次Firestore流数据时, 侦听所有更改并更新商店。
this.firestore.collection$().pipe( tap(employees => { this.store.patch({ loading: false, employees, }, `employees collection subscription`) }) ).subscribe()

employee $()和loading $()函数将选择我们想要稍后在组件上使用的状态。当状态加载时, employee $()将返回一个空数组。这将使我们能够在视图上显示正确的消息。
get employees$(): Observable< Employee[]> { return this.store.state$.pipe(map(state => state.loading ? [] : state.employees)) }get loading$(): Observable< boolean> { return this.store.state$.pipe(map(state => state.loading)) }

好的, 现在我们已经准备好所有服务, 并且可以构建视图组件。但是在我们这样做之前, 可能需要快速复习一下……
RxJs Observables和异步管道
观测值允许订户以流的形式接收数据的发射。与异步管道结合使用, 可以非常强大。
异步管道负责订阅Observable并在发出新数据时更新视图。更重要的是, 当组件被销毁时, 它将自动退订, 从而保护我们免受内存泄漏的影响。
你可以在官方文档中大致了解有关Observables和RxJs库的更多信息。
创建视图组件 在employee / components / employees-page / employees-page.component.html中, 我们将输入以下代码:
< div class="container"> < div class="row"> < div class="col-12 mb-3"> < h4> Employees < /h4> < /div> < /div> < div class="row"> < div class="col-6"> < app-employees-list> < /app-employees-list> < /div> < div class="col-6"> < app-employees-form> < /app-employees-form> < /div> < /div> < /div>

同样, employees / components / employees-list / employees-list.component.html将使用上述异步管道技术进行操作:
< div *ngIf="loading$ | async"> Loading... < /div> < div *ngIf="noResults$ | async"> No results < /div> < div class="card bg-light mb-3" style="max-width: 18rem; " *ngFor="let employee of employees$ | async"> < div class="card-header"> {{employee.location}}< /div> < div class="card-body"> < h5 class="card-title"> {{employee.name}}< /h5> < p class="card-text"> {{employee.hasDriverLicense ? 'Can drive': ''}}< /p> < button (click)="delete(employee)" class="btn btn-danger"> Delete< /button> < /div> < /div>

但是在这种情况下, 我们也需要该组件的一些TypeScript代码。文件employee / components / employees-list / employees-list.component.ts将需要以下内容:
import { Employee } from '../../models/employee'; import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { EmployeesService } from '../../services/employees.service'; @Component({ selector: 'app-employees-list', templateUrl: './employees-list.component.html', styleUrls: ['./employees-list.component.scss'] }) export class EmployeesListComponent implements OnInit { loading$: Observable< boolean> ; employees$: Observable< Employee[]> ; noResults$: Observable< boolean> ; constructor( private employees: EmployeesService ) {}ngOnInit() { this.loading$ = this.employees.loading$; this.noResults$ = this.employees.noResults$; this.employees$ = this.employees.employees$; }delete(employee: Employee) { this.employees.delete(employee.id); }}

因此, 转到浏览器, 我们现在拥有的是:
使用Firebase在Angular中进行状态管理

文章图片
控制台将具有以下输出:
使用Firebase在Angular中进行状态管理

文章图片
看到这一点, 我们可以知道Firestore用空值流传输了employees集合, 并且employees-page存储被修补, 将加载从true设置为false。
好的, 让我们构建表单以将新员工添加到Firestore:
员工表格 在employees / components / employees-form / employees-form.component.html中, 我们将添加以下代码:
< form [formGroup]="form" (ngSubmit)="submit()"> < div class="form-group"> < label for="name"> Name< /label> < input type="string" class="form-control" id="name" formControlName="name" [class.is-invalid]="isInvalid('name')"> < div class="invalid-feedback"> Please enter a Name. < /div> < /div> < div class="form-group"> < select class="custom-select" formControlName="location" [class.is-invalid]="isInvalid('location')"> < option value="" selected> Choose location< /option> < option *ngFor="let loc of locations" [ngValue]="loc"> {{loc}}< /option> < /select> < div class="invalid-feedback"> Please select a Location. < /div> < /div> < div class="form-group form-check"> < input type="checkbox" class="form-check-input" id="hasDriverLicense" formControlName="hasDriverLicense"> < label class="form-check-label" for="hasDriverLicense"> Has driver license< /label> < /div> < button [disabled]="form.invalid" type="submit" class="btn btn-primary d-inline"> Add< /button> < span class="ml-2"> {{ status$ | async }}< /span> < /form>

相应的TypeScript代码将存在于employee / components / employees-form / employees-form.component.ts中:
import { EmployeesService } from './../../services/employees.service'; import { AngularFirestore } from '@angular/fire/firestore'; import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Observable } from 'rxjs'; @Component({ selector: 'app-employees-form', templateUrl: './employees-form.component.html', styleUrls: ['./employees-form.component.scss'] }) export class EmployeesFormComponent implements OnInit {form: FormGroup = new FormGroup({ name: new FormControl('', Validators.required), location: new FormControl('', Validators.required), hasDriverLicense: new FormControl(false) }); locations = [ 'Rosario', 'Buenos Aires', 'Bariloche' ]status$: Observable < string > ; constructor( private employees: EmployeesService ) {}ngOnInit() { this.status$ = this.employees.formStatus$; }isInvalid(name) { return this.form.controls[name].invalid & & (this.form.controls[name].dirty || this.form.controls[name].touched) }async submit() { this.form.disable() await this.employees.create({ ...this.form.value }) this.form.reset() this.form.enable() }}

该表单将调用EmployeesService的create()方法。现在页面看起来像这样:
使用Firebase在Angular中进行状态管理

文章图片
让我们看看添加新员工时会发生什么。
添加新员工
添加新员工后, 我们将看到以下内容输出到控制台:
使用Firebase在Angular中进行状态管理

文章图片
这些都是添加新员工时触发的所有事件。让我们仔细看看。
当我们调用create()时, 我们将执行以下代码, 将loading = true, formStatus =’ Saving … ’ 并将employees数组设置为空(上图中的(1))。
this.store.patch({ loading: true, employees: [], formStatus: 'Saving...' }, "employee create") return this.firestore.create(employee).then(_ => { this.store.patch({ formStatus: 'Saved!' }, "employee create SUCCESS") setTimeout(() => this.store.patch({ formStatus: '' }, "employee create timeout reset formStatus"), 2000) }).catch(err => { this.store.patch({ loading: false, formStatus: 'An error ocurred' }, "employee create ERROR") })

接下来, 我们调用基本的Firestore服务来创建员工, 该员工将记录日志(4)。在promise回调中, 我们设置formStatus =’ Saved!’ 。并记录(5)。最后, 我们设置超时以将formStatus设置为空, 并进行日志记录(6)。
日志事件(2)和(3)是由Firestore订阅employee集合触发的事件。实例化EmployeesService时, 我们订阅该集合, 并在每次发生更改时接收该集合。
通过将employees数组设置为来自Firestore的雇员, 这将为loading = false的商店设置一个新状态。
如果我们扩展日志组, 则会看到每个事件和商店更新的详细数据, 以及上一个值和下一个值, 这对于调试非常有用。
使用Firebase在Angular中进行状态管理

文章图片
这是添加新员工后页面的外观:
使用Firebase在Angular中进行状态管理

文章图片
添加摘要组件
假设我们现在要在页面上显示一些摘要数据。假设我们需要员工总数, 司机人数以及来自Rosario的人数。
首先, 将新的状态属性添加到employee / states / employees-page.ts中的页面状态模型中:
// ... export interface EmployeesPage {loading: boolean; employees: Employee[]; formStatus: string; totalEmployees: number; totalDrivers: number; totalRosarioEmployees: number; }

然后, 我们将在员工/服务/emplyees-page.store.ts中的商店中对其进行初始化:
// ... constructor() { super({ loading: true, employees: [], totalDrivers: 0, totalEmployees: 0, totalRosarioEmployees: 0 }) } // ...

接下来, 我们将计算新属性的值, 并将它们各自的选择器添加到EmployeesService中:
// ...this.firestore.collection$().pipe( tap(employees => { this.store.patch({ loading: false, employees, totalEmployees: employees.length, totalDrivers: employees.filter(employee => employee.hasDriverLicense).length, totalRosarioEmployees: employees.filter(employee => employee.location === 'Rosario').length, }, `employees collection subscription`) }) ).subscribe()// ...get totalEmployees$(): Observable < number > { return this.store.state$.pipe(map(state => state.totalEmployees)) }get totalDrivers$(): Observable < number > { return this.store.state$.pipe(map(state => state.totalDrivers)) }get totalRosarioEmployees$(): Observable < number > { return this.store.state$.pipe(map(state => state.totalRosarioEmployees)) }// ...

现在, 让我们创建摘要组件:
ng g c employees/components/EmployeesSummary

我们将其放在employee / components / employees-summary / employees-summary.html中:
< p> < span class="font-weight-bold"> Total:< /span> {{total$ | async}} < br> < span class="font-weight-bold"> Drivers:< /span> {{drivers$ | async}} < br> < span class="font-weight-bold"> Rosario:< /span> {{rosario$ | async}} < br> < /p>

并在员工/组件/员工摘要/employees-summary.ts中:
import { Component, OnInit } from '@angular/core'; import { EmployeesService } from '../../services/employees.service'; import { Observable } from 'rxjs'; @Component({ selector: 'app-employees-summary', templateUrl: './employees-summary.component.html', styleUrls: ['./employees-summary.component.scss'] }) export class EmployeesSummaryComponent implements OnInit {total$: Observable < number > ; drivers$: Observable < number > ; rosario$: Observable < number > ; constructor( private employees: EmployeesService ) {}ngOnInit() { this.total$ = this.employees.totalEmployees$; this.drivers$ = this.employees.totalDrivers$; this.rosario$ = this.employees.totalRosarioEmployees$; }}

然后, 我们将组件添加到employee / employees-page / employees-page.component.html:
// ... < div class="col-12 mb-3"> < h4> Employees < /h4> < app-employees-summary> < /app-employees-summary> < /div> // ...

结果如下:
使用Firebase在Angular中进行状态管理

文章图片
在控制台中, 我们有:
使用Firebase在Angular中进行状态管理

文章图片
员工服务计算每个排放的total totalEmployees, totalDrivers和totalRosarioEmployees并更新状态。
本教程的完整代码可在GitHub上找到, 并且还有一个实时演示。
使用Observables管理Angular应用程序状态…检查! 在本教程中, 我们介绍了一种使用Firebase后端在Angular应用程序中管理状态的简单方法。
这种方法非常适合使用Observables的Angular准则。通过跟踪应用程序状态的所有更新, 它还有助于调试。
通用商店服务还可以用于管理不使用Firebase功能的应用程序的状态, 以仅管理应用程序的数据或来自其他API的数据。
但是, 在不加选择地应用此功能之前, 需要考虑的一件事是, EmployeesService在构造函数上订阅了Firestore, 并在应用程序处于活动状态时保持监听。如果我们在应用程序的多个页面上使用员工列表, 这可能会很有用, 以避免在页面之间导航时从Firestore获取数据。
但这在其他情况下可能不是最好的选择, 例如, 你只需要提取一次初始值, 然后手动触发从Firebase重新加载数据。最重要的是, 了解你的应用程序要求以选择更好的实施方法总是很重要的。

    推荐阅读