Angular 6 - HttpClient在服务中保留订阅,但将结果传递给组件

Mar*_*018 7 typescript angular angular-httpclient angular6

我有一个preject包含一个服务(获取数据)和一个组件(显示它).

我想在app.component.ts上将代码保持在最低限度.

在我的服务中:

getPosts() {
    return this.http.get('https://jsonplaceholder.typicode.com/posts', httpOptions).subscribe(
      result => {
        return result;
        this.theData = result;
      },
      error => {
        return error;
      }
    );
  }
Run Code Online (Sandbox Code Playgroud)

在我的app.component.ts中:

 getPostsFromService() {
    this.myService.getPosts();
  }
Run Code Online (Sandbox Code Playgroud)

但是,当然,我需要得到结果并将其传递给我的组件,但这样的事情是行不通的:

myData;

  ...


  getPostsFromService() {
    this.myData = this.myService.getPosts();
  }
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,我该怎么做或者是否真的建议在我的组件上调用subscribe而不是在服务中?

Vik*_*kas 5

在新的HttpClientModule 中, JSON 是假定的默认值,不再需要使用显式解析res.json()

您可以告诉HttpClient响应的类型,以便更容易、更明显地使用输出。

响应的类型检查可以通过使用类型参数
Create an Interface来完成

export interface Idata{
  userId:number;
  Id:number;
  title:string;
  body:string;
}
Run Code Online (Sandbox Code Playgroud)

Http返回一个observableand 我们可以告诉HttpClient.get返回response为 Idata 类型 当我们使用http.get<Idata[]>(...)then 它返回Observable<Idata[]>类型的实例。
为您服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {Observable} from 'rxjs';
import {Idata} from './Idata'
@Injectable()
export class ShareService {

    constructor(private httpc:HttpClient)
    {
    }

    public getPosts():Observable<Idata[]>
    {
        return this.httpc.get<Idata[]>('https://jsonplaceholder.typicode.com/posts');
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的组件subscribe中Observable<Idata[]>获取 Idata 的实例

  public data:Array<Idata>=[];
  constructor(public service:ShareService)
  {
     this.service.getPosts().subscribe(value => {
        this.data=value;
     });
  }
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用async管道 AsyncPipe接受 anobservable或 a作为参数promise,调用subscribe或附加 then 处理程序,然后在将异步结果传递给调用者之前等待异步结果。

public response:Observable<Idata[]>;
constructor(public service:ShareService)
{
    this.response=this.service.getPosts();
}
Run Code Online (Sandbox Code Playgroud)

HTML

<div *ngFor="let item of (response|async)">
  {{item.body}}
</div>
Run Code Online (Sandbox Code Playgroud)


现场演示

我的问题是,我该怎么做,还是真的建议在我的组件上调用 subscribe 而不是在服务中?

将复杂的组件逻辑委托给服务是一种很好的做法

来自Angular Style Guide
将组件中的逻辑限制为视图所需的逻辑。所有其他逻辑都应该委托给服务。

务必将可重用逻辑移至服务并保持组件简单并专注于其预期目的。

为什么?当逻辑被放置在一个服务中并通过一个函数公开时,它可以被多个组件重用。

为什么?在单元测试中可以更轻松地隔离服务中的逻辑,而可以轻松模拟组件中的调用逻辑。

为什么?从组件中删除依赖项并隐藏实现细节。

为什么?保持组件纤薄、修剪和集中。

在 Component 中订阅允许您http与多个共享单个请求observers,如果您不这样做,您将违反DRY 原则
P:S 要http为多个共享单个请求observers,您需要类似share 运算符的东西。

import {Observable} from 'rxjs';
import {share} from 'rxjs/operators'

export class dataService {

    public data$=Observable<Idata[]>
    constructor(http:HttpClient)
    {
        this.data$=this.http.get<Idata[]>('https://jsonplaceholder.typicode.com/posts').pipe(share());
    }
    public getPosts():Observable<Idata[]>
    {
        return this.data$
    }
}
Run Code Online (Sandbox Code Playgroud)

这个操作符是一个特化publish,当观察者的数量从 0 到 1 时,它会创建一个订阅,然后与所有后续观察者共享该订阅,直到观察者的数量归零,此时订阅被处理。