首页 文章

组件BehaviorSubject订阅服务器不接收异步http请求发出的值

提问于
浏览
0

我试图理解为什么这个BehaviorSubject订阅者不接收发出的值 .

在我的组件ngOnInit中,我将订阅服务器设置为一个返回对BehaviorSubject的引用的服务方法:

// project-detail.component.ts
 ngOnInit() {
  this.activatedRoute.params.subscribe((data: Params)  => {
    if (data && data.id) {
      this.projectService.getProject(data.id).subscribe(project => {
        console.log(project);
      });
    }
  });
 }

在服务中,我发出一个http请求,然后将响应数据推送到BehaviorSubject的下一个方法:

// project.service.ts
 import { HttpClient } from '@angular/common/http';  
 import { BehaviorSubject, Observable } from 'rxjs';

 @Injectable()
 export class ProjectService {
 private apiUrl = envLocal.apiJsonServerUrl;
 private currentProjectObs$ = new BehaviorSubject<IProject>(null);

 constructor(private http: HttpClient) {
 }

 getProject(id: number = 0) {
  if (id) {
    this.http.get(`${this.apiUrl}/projects/${id}`)
      .subscribe(project => {
        this.currentProjectObs$.next(project);
      });
  }
  return this.currentProjectObs$;
 }

我的理解是我的组件的ngOnInit中的订阅者应该监听从getProject返回的BehaviorSubject引用的更改(即currentProjectObs $) .

当ngOnInit首次运行时,它调用getProject,并且由于getProject内的http调用是异步的,因此返回currentProjectObs $,初始值为null . 但是一旦http get请求完成,currentProjectObs $ .next(项目)就会被调用,我希望,ngOnInit中的订阅者可以接收新发出的值 - 但这不会发生 .

我想了解这里发生了什么以及为什么订阅者没有从http请求中收到异步值,以及如何修复它以便它 .

2 回答

  • 0

    当你使用下面的函数时,它将再次返回null值,因为它不会等待api调用 . 如果您使用的是 Behavior subject ,则可以直接从行为主题中获取值,您无需返回它 .

    getProject(id: number = 0) {
      if (id) {
        this.http.get(`${this.apiUrl}/projects/${id}`)
          .subscribe(project => {
            this.currentProjectObs$.next(project);
          });
      }
      return this.currentProjectObs$;
    }
    

    您可以使用这两种类型来完成 . 把它改成这样的东西:

    1. Without use of behavior subject.

    // Your Service 
    getProject(id: number = 0): Observable<any> {
        if (id) {
           return this.http.get(`${this.apiUrl}/projects/${id}`)
              .pipe(map(project => {
                   return project;
                   // this.currentProjectObs$.next(project);
              });
        }
        return Observable.of(null);
    };
    
    // Your Component
    ngOnInit() {
      this.activatedRoute.params.subscribe((data: Params)  => {
        if (data && data.id) {
          this.projectService.getProject(data.id)
            .subscribe(project => {
                console.log(project);
          });
        }
      });
    }
    

    2. Use With Behavior subject

    // Your service
    
    public currentProjectObs$ = new BehaviorSubject<IProject>(null);
    
    getProject(id: number = 0) {
      if (id) {
        this.http.get(`${this.apiUrl}/projects/${id}`)
          .pipe(map(project => {
            this.currentProjectObs$.next(project);
          });
      }
      // return this.currentProjectObs$;
    }
    
    // Your component
    this.activatedRoute.params.subscribe((data: Params)  => {
        if (data && data.id) {
          this.projectService.getProject(data.id);
        }
    });
    
    this.projectService.currentProjectObs$
       .subscribe(project => {
           if(project){
              console.log(project);
           }
    })
    
  • 0

    我认为您的代码可以简化一下:

    // project-detail.component.ts
     ngOnInit() {
      this.activatedRoute.params.pipe(switchMap(params => {
           if (data && data.id) {
              return this.projectService.getProject(data.id)    
           }
         // return observable of undefined in case id was not found
         return of(undefined);
    
      })).subscribe(actualData  => {
         console.log("actual data returned by api: ", actualData)
      });
     }
    

    在您的服务中:

    // project.service.ts
     import { HttpClient } from '@angular/common/http';  
     import { BehaviorSubject, Observable } from 'rxjs';
    
     @Injectable()
     export class ProjectService {
     private apiUrl = envLocal.apiJsonServerUrl;
    
     constructor(private http: HttpClient) {
     }
    
     getProject(id: number = 0) {
        return this.http.get(`${this.apiUrl}/projects/${id}`);
     }
    

    当您确实需要数据执行某些操作时,您应该只在最后订阅 . 使用Rxjs运算符,数据可以在一个可观察对象之间流动 . 切换映射订阅第一个observable并返回我们在结尾处订阅的另一个 .

    如果这对您有用,请告诉我 .

相关问题