在 Angular 个组件之间共享使用 HttpClient 检索的数据

Share data retrieved using HttpClient between Angular components

我想创建一个服务方法,它在第一次执行时会从 URL 中获取数据集,缓存数据集,然后与随后调用服务的组件共享数据集的相同实例方法。

我已经开始创建两个解决方案。这两种解决方案的问题是,在加载 Angular 应用程序后的第一毫秒内,他们多次从 URL 获取数据集, and/or 他们向控制台抛出一些错误消息,但是在两个组件之间进行第一次或第二次导航后,数据似乎已正确共享,并且不再往返于 URL.

方法 #1

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class FirstService {
  private url = 'http://somedummydomain.com/api/entries';
  private data: any;
  private observable: Observable<any>;

  constructor(private http: HttpClient) {}

  getData() : Observable<any> {
    if (this.data) {
      return of(this.data);
    } else if (this.observable) {
      return this.observable;
    } else {
      this.observable = this.http.get(this.url);
      this.observable.subscribe((data) => {
        this.data = data;
        this.observable = null;
      });
      return this.observable;
    }
  }
}

方法 #2

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class SecondService {
  private sharedData: BehaviorSubject<any> = new BehaviorSubject<any>(null);
  private url = 'http://somedummydomain.com/api/entries';

  constructor(private http: HttpClient) {
    this.http.get(this.url).subscribe((data) => {
      this.addData(data);
    });
  }

  private addData(data: any) {
    this.sharedData.next(data);
  }

  getData(): Observable<any> {
    return this.sharedData.asObservable();
  }
}

库版本

谢谢!

如果我正确理解你的问题,你需要从 url 中获取数据并在组件之间共享。为什么不在加载组件之前获取数据?如果您可以在加载应用程序之前获取数据,那么您可以使用 app-initializer

https://dzone.com/articles/how-to-use-the-app-initializer-token-to-hook-into

为了完整起见,这里是 反应式 方式来解决您的需求(在订阅者之间共享数据):

@Injectable({
  providedIn: 'root',
})
export class SecondService {
  private url = 'http://somedummydomain.com/api/entries';
  private data$: Observable<any>;

  constructor(private http: HttpClient) {
    this.data$ = this.http.get(this.url).pipe(
      shareReplay(1)
    );
  }

  getData(): Observable<any> {
    return this.data$;
  }
}

shareReplay 运算符将做两件事:

  1. 它将共享 Observable - 这意味着所有订阅者将收到相同的通知并且源仅被订阅一次。方法 1 对您来说失败了,因为每个订阅者都会再次触发 HTTP GET,直到第一个请求完成并且您到达 this.data !== undefined 分支。
  2. 它将重播最后N条通知(在本例中只有最后一条通知)给所有来得太晚的订阅者——即在HTTP调用之后订阅的订阅者返回一个值。如果您不需要它,请改用 share

如果您需要 data 作为 属性,您可以使用 tap 运算符设置它,如下所示:

this.data$ = this.http.get(this.url).pipe(
  tap(data => this.data = data),
  shareReplay(1)
);