龙空技术网

在 Angular 中使用 RxJS 声明式模式进行数据操作

庄志炎 930

前言:

现在你们对“angular请求数据”都比较注意,姐妹们都想要知道一些“angular请求数据”的相关知识。那么小编在网络上收集了一些关于“angular请求数据””的相关内容,希望大家能喜欢,姐妹们一起来学习一下吧!

在 Angular 中使用声明性 RxJS 模式操作数据

虽然命令式和声明式编程风格都可以在正确的上下文中增加价值,但将某些代码的执行委托给编程语言可以优化时序。

通过在 Angular 中使用 RxJS 声明模式,我们可以委托执行某些代码以在模板中需要数据时获取数据。

例子,

// app.component.html<div *ngIf="data$ | async as data">  {{ data.title }}</div>

通过使用异步管道,我们不需要订阅或取消订阅 observable。 Angular 会自动处理它。

但是,一旦加载模板,异步管道就会获取数据并按原样显示。

通常我们需要在显示数据之前对其进行操作。 为此,我们可以使用一些 RxJS 运算符在数据到达模板之前对其进行操作。

声明性数据操作

想一想这样一种情况,您从 HTTP 调用接收数据并希望在使其在组件中可用之前对其进行操作。

例如,我们将使用 HttpClient 服务从服务器获取数据。 “异步方法发送一个 HTTP 请求,并返回一个 Observable,当收到响应时发出请求的数据”,angular.io。

import { HttpClient } from '@angular/common/http';import { Injectable } from '@angular/core';import { tap } from 'rxjs/operators';@Injectable({ providedIn: 'root' })export class TodoService {  private todoUrl = ';;  constructor(private http: HttpClient) {}  todo$ = this.http.get(this.todoUrl).pipe(tap(console.log));}

在我们的示例中,Observable 包含一个具有特定形状的对象,因此我们可以创建如下接口:

interface ToDo {  userId: number;  id: number;  title: string;  completed: boolean;}

我们想在显示之前更改标题键的值。

经典图案

按照命令式模式,我们将使用 subscribe 方法订阅 Observable,可能在 ngOnInit 中。

然后我们将结果分配给一个变量,并最终在需要时操纵该变量。

例如,以下代码将订阅结果分配给订阅变量。

import { Component, OnDestroy, OnInit } from '@angular/core';import { Subscription } from 'rxjs';import { TodoService } from './todo.service';import { ToDo } from './model';@Component({  selector: 'my-app',  templateUrl: './app.component.html',  styleUrls: ['./app.component.css'],})export class AppComponent implements OnInit, OnDestroy {  subscription: Subscription;  data: ToDo;  constructor(private todoService: TodoService) {}  ngOnInit(): void {    this.subscription = this.todoService      .getTodo()      .subscribe((todo) => (this.data = todo));    console.log(this.data);  }  ngOnDestroy(): void {    this.subscription.unsubscribe();  }}

如果我们需要更改订阅变量的值,我们可能会创建一个方法,该方法接受订阅并在模板中使用它之前更改标题。

声明性数据操作

在尝试声明性时,您可能想知道如何在不依赖于使用 subscribe 方法的情况下操作数据。

这是最初的声明性代码:

import { Component } from '@angular/core';import { TodoService } from './todo.service';@Component({  selector: 'my-app',  templateUrl: './app.component.html',  styleUrls: ['./app.component.css'],})export class AppComponent {  data$ = this.todoService.todo$;  constructor(private todoService: TodoService) {}}

第 10 行是起点。

我们定义了一个名为 data$ 的本地属性,并将服务中的 Observable 分配给该属性,以使其在组件中可用。

如果您没有阅读 Angular 中的 RxJS 声明模式,请注意此时我们的代码并未“执行” Observable!

换句话说,没有与从服务器获取数据相关的网络请求。 这里没有任何事情发生。 data$ 是一个空的 observable。

当我们订阅 Observable 或在模板中使用异步管道时,data$ 的值会发生变化。

如上所述,前一个选项与反应式方法背道而驰,因此我们只剩下异步管道。 然而,一旦 Angular 渲染了组件视图,异步管道就会触发 data$ 并显示我们从 Observable 获得的任何内容。

因此,我们需要在从服务中获取数据之后以及在异步管道“调用”数据之前对其进行操作。

为此,我们将使用 RxJS 管道 API 和 RxJS 映射运算符。

RxJS 管道

我们可以使用如下管道:

data$ = this.todoService.todo$.pipe(  operator1(),  operator2(),  operatorN());

简而言之:

我们从服务接收到的 Observable 进入 pipe()。它通过第一个运算符并根据提供的返回新 Observable 的函数进行操作。新的 Observable 进入第二个运算符,根据提供的函数进行操作,依此类推,直到管道中的最后一个运算符。最后,一旦我们订阅了 Observable,它就会存储在 data$ 中。否则,我们只是声明了我们想要获取的内容,但 data$ 仍然是空的,直到我们在模板中使用异步管道。

RxJS 地图运算符

按照上面的代码,我们将使用 RxJS 映射运算符来操作 Observable,然后再将其提供给异步管道。

简而言之,我们可以说 map 运算符通过我们提供的函数转换每个发射的项目。

它订阅输入流,根据提供的函数转换接收到的项目,并使用转换后的项目创建输出流。

RxJS 的 map 操作符与 JavaScriptmap() 方法非常相似,可以如下使用:

data$ = this.todoService.todo$.pipe(  map((x) => ({     ...x,     title: x.title + 'and more'   })));

我们从服务接收到的 Observable 进入管道,通过我们在 map 操作符中提供的函数,然后退出管道。

在 map 运算符中,我们声明了一个匿名函数 () => {},它接受一个参数 x 并返回一个对象。

由于展开语法,返回的对象具有我们传入的对象的所有键值对,但我们更改了标题的值以添加字符串“等等”。

更准确地说,我们甚至可以声明参数x的类型,这样代码就变成了:

import { Component } from '@angular/core';import { TodoService } from './todo.service';import { map } from 'rxjs/operators';interface ToDo {  userId: number;  id: number;  title: string;  completed: boolean;}@Component({  selector: 'my-app',  templateUrl: './app.component.html',  styleUrls: ['./app.component.css'],})export class AppComponent {  data$ = this.todoService.todo$.pipe(    map((x: ToDo) => ({      ...x,      title: x.title + ' and more',    }))  );  constructor(private todoService: TodoService) {}}

您可能希望在另一个文件中声明接口以使其在其他地方可用。 在这种情况下,更容易在同一个片段中看到它。

关于声明性数据操作的注意事项

但是,似乎进行某些操作所需的代码量可能会迅速增加。

因此,使用声明性模式的好处可能会被“太多代码”的成本所抵消。

代码太多?

声明式代码以其高抽象级别而著称。

开发人员可以以压缩的方式表示复杂的模式。 然而,程序越复杂,代码变得如此复杂以至于只有最初编写它的开发人员才能阅读的风险就越高。

这不好。

通常,如果在团队中工作,我们希望能够在不依赖单个人的知识的情况下维护和构建应用程序。

此外,在业务环境中,可能有必要花更多时间在新员工或外部开发人员的培训上,以便他们完全理解代码结构。

总而言之,它甚至可能会增加您的成本。

标签: #angular请求数据