Angular 12 RxJs BehaviourSubject 和 HTTP Get 请求问题
Angular 12 RxJs BehaviourSubject and HTTP Get request issue
我是 RxJs 的新手,在我的应用程序中使用 BehaviourSubject 时从 HTTP 请求获取响应时遇到问题。这样做的正确方法是什么?
通过使用 chrome 开发工具,我注意到该函数甚至没有进行网络调用。在尝试使用 BehaviourSubject 之前,我只使用了一个简单的 Observable 并且 http 请求有效。我还注意到只是发回一些静态数据而不是做一个 http 请求然后主题工作。
//Service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { tap } from 'rxjs/operators';
import { Pokemon } from '../_model/pokemon';
@Injectable({
providedIn: 'root'
})
export class PokemonService {
baseUrl = environment.apiUrl;
private pokemonListSubject = new BehaviorSubject<any>(null);
pokemonList$: Observable<Pokemon> = this.pokemonListSubject.asObservable();
constructor(private http: HttpClient) { }
getPokemonList2(){
//This request works
//this.pokemonListSubject.next('this is a pokemon')
this.http.get<Pokemon>(this.baseUrl + `pokemon/ditto`)
.pipe(
tap(value => {
this.pokemonListSubject.next(value)
})
)
}
}
//component
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { Gen } from 'src/app/_model/gen';
import { Pokemon } from 'src/app/_model/pokemon';
import { GensService } from 'src/app/_services/gens.service';
import { PokemonService } from 'src/app/_services/pokemon.service';
@Component({
selector: 'app-screen',
templateUrl: './screen.component.html',
styleUrls: ['./screen.component.css']
})
export class ScreenComponent implements OnInit {
gens$: Observable<Gen[]>;
pokemon2$?: any;
constructor(public pokemonService: PokemonService, private genService: GensService) {
this.gens$ = this.genService.getGens();
this.pokemonService.pokemonList$.subscribe(pokemonList => this.pokemon2$ = pokemonList)
}
ngOnInit(): void {}
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2();
}
}
//html
<div id="screen">
<div class="pokedex">
<ul>
<li *ngFor="let gen of (gens$ | async)"> <a (click)="getPokemonByGen2(gen)">{{gen.name}}</a></li>
</ul>
</div>
<ng-container *ngIf="pokemon2$" >
{{pokemon2$.name}}
</ng-container>
</div>
使用下面给出的方法,
getPokemonList2(): void {
//This request works
//this.pokemonListSubject.next('this is a pokemon')
this.http.get<Pokemon>(this.baseUrl + `pokemon/ditto`)
.subscribe(val => {
this.pokemonList$.next(val);
});
}
您的构造函数中不应该有 任何 逻辑,这就是 ngOnInit
的用途。对于任何逻辑初始化和监听变化,在这种情况下,您的主题 ngOnInit
是处理它的正确位置。
现在,在您的点击事件中,您正在调用您的服务,但是没有人订阅该 HTTP 调用。您只是订阅了您的主题。
您的代码中缺少的是:
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2().subscribe();
}
此外,您正在订阅自己的特殊可观察对象,也就是 pokemonList$
很好,但是您没有处理订阅。您需要存储该订阅,以便在您导航到其他地方时可以“销毁”它,否则,您将在您的应用程序上造成内存泄漏。
....
....
mySubscription!: Subscription;
ngOnInit(): void {
this.mySubscription = this.pokemonService.pokemonList$
.subscribe(pokemonList => this.pokemon2$ = pokemonList);
}
ngOnDestroy(): void {
this.mySubscription?.unsubscribe();
}
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2().subscribe();
}
现在,如果您不想处理订阅,而不是订阅您的 pokemonList$
,您可以通过管道将其存储在本地 属性 中,如:
ngOnInit(): void {
this.pokemon2$ = this.pokemonService.pokemonList$
.pipe(
map((pokemonList) => pokemonList)
);
}
我是 RxJs 的新手,在我的应用程序中使用 BehaviourSubject 时从 HTTP 请求获取响应时遇到问题。这样做的正确方法是什么? 通过使用 chrome 开发工具,我注意到该函数甚至没有进行网络调用。在尝试使用 BehaviourSubject 之前,我只使用了一个简单的 Observable 并且 http 请求有效。我还注意到只是发回一些静态数据而不是做一个 http 请求然后主题工作。
//Service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { tap } from 'rxjs/operators';
import { Pokemon } from '../_model/pokemon';
@Injectable({
providedIn: 'root'
})
export class PokemonService {
baseUrl = environment.apiUrl;
private pokemonListSubject = new BehaviorSubject<any>(null);
pokemonList$: Observable<Pokemon> = this.pokemonListSubject.asObservable();
constructor(private http: HttpClient) { }
getPokemonList2(){
//This request works
//this.pokemonListSubject.next('this is a pokemon')
this.http.get<Pokemon>(this.baseUrl + `pokemon/ditto`)
.pipe(
tap(value => {
this.pokemonListSubject.next(value)
})
)
}
}
//component
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { Gen } from 'src/app/_model/gen';
import { Pokemon } from 'src/app/_model/pokemon';
import { GensService } from 'src/app/_services/gens.service';
import { PokemonService } from 'src/app/_services/pokemon.service';
@Component({
selector: 'app-screen',
templateUrl: './screen.component.html',
styleUrls: ['./screen.component.css']
})
export class ScreenComponent implements OnInit {
gens$: Observable<Gen[]>;
pokemon2$?: any;
constructor(public pokemonService: PokemonService, private genService: GensService) {
this.gens$ = this.genService.getGens();
this.pokemonService.pokemonList$.subscribe(pokemonList => this.pokemon2$ = pokemonList)
}
ngOnInit(): void {}
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2();
}
}
//html
<div id="screen">
<div class="pokedex">
<ul>
<li *ngFor="let gen of (gens$ | async)"> <a (click)="getPokemonByGen2(gen)">{{gen.name}}</a></li>
</ul>
</div>
<ng-container *ngIf="pokemon2$" >
{{pokemon2$.name}}
</ng-container>
</div>
使用下面给出的方法,
getPokemonList2(): void {
//This request works
//this.pokemonListSubject.next('this is a pokemon')
this.http.get<Pokemon>(this.baseUrl + `pokemon/ditto`)
.subscribe(val => {
this.pokemonList$.next(val);
});
}
您的构造函数中不应该有 任何 逻辑,这就是 ngOnInit
的用途。对于任何逻辑初始化和监听变化,在这种情况下,您的主题 ngOnInit
是处理它的正确位置。
现在,在您的点击事件中,您正在调用您的服务,但是没有人订阅该 HTTP 调用。您只是订阅了您的主题。
您的代码中缺少的是:
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2().subscribe();
}
此外,您正在订阅自己的特殊可观察对象,也就是 pokemonList$
很好,但是您没有处理订阅。您需要存储该订阅,以便在您导航到其他地方时可以“销毁”它,否则,您将在您的应用程序上造成内存泄漏。
....
....
mySubscription!: Subscription;
ngOnInit(): void {
this.mySubscription = this.pokemonService.pokemonList$
.subscribe(pokemonList => this.pokemon2$ = pokemonList);
}
ngOnDestroy(): void {
this.mySubscription?.unsubscribe();
}
getPokemonByGen2(gen: Gen){
this.pokemonService.getPokemonList2().subscribe();
}
现在,如果您不想处理订阅,而不是订阅您的 pokemonList$
,您可以通过管道将其存储在本地 属性 中,如:
ngOnInit(): void {
this.pokemon2$ = this.pokemonService.pokemonList$
.pipe(
map((pokemonList) => pokemonList)
);
}