在 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();
}
}
库版本
- angular: v9.1.9
- rxjs: v6.5.5
谢谢!
如果我正确理解你的问题,你需要从 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
运算符将做两件事:
- 它将共享 Observable - 这意味着所有订阅者将收到相同的通知并且源仅被订阅一次。方法 1 对您来说失败了,因为每个订阅者都会再次触发 HTTP GET,直到第一个请求完成并且您到达
this.data !== undefined
分支。
- 它将重播最后N条通知(在本例中只有最后一条通知)给所有来得太晚的订阅者——即在HTTP调用之后订阅的订阅者返回一个值。如果您不需要它,请改用
share
。
如果您需要 data
作为 属性,您可以使用 tap
运算符设置它,如下所示:
this.data$ = this.http.get(this.url).pipe(
tap(data => this.data = data),
shareReplay(1)
);
我想创建一个服务方法,它在第一次执行时会从 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();
}
}
库版本
- angular: v9.1.9
- rxjs: v6.5.5
谢谢!
如果我正确理解你的问题,你需要从 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
运算符将做两件事:
- 它将共享 Observable - 这意味着所有订阅者将收到相同的通知并且源仅被订阅一次。方法 1 对您来说失败了,因为每个订阅者都会再次触发 HTTP GET,直到第一个请求完成并且您到达
this.data !== undefined
分支。 - 它将重播最后N条通知(在本例中只有最后一条通知)给所有来得太晚的订阅者——即在HTTP调用之后订阅的订阅者返回一个值。如果您不需要它,请改用
share
。
如果您需要 data
作为 属性,您可以使用 tap
运算符设置它,如下所示:
this.data$ = this.http.get(this.url).pipe(
tap(data => this.data = data),
shareReplay(1)
);