首页 > 解决方案 > BehaviorSubject 不发射值

问题描述

在我的 Angular 7 应用程序中,我有一个登录服务,用于跟踪此人是否登录和一个管理员。由于某种原因,只能看到该方法的初始true值。login在服务中我有这个:

private admin = new BehaviorSubject(false);
admin$ = this.admin.asObservable();

login(user: string, pwd: string): Observable<ILoginData> {
    sessionStorage.removeItem('admin');

    const coded = btoa(`${user}:${pwd}`);
    const headers = new HttpHeaders({
        'Authorization': `Basic ${coded}`,
    });

    return this.http
        .post<ILoginData>(`${this.baseUrl}/login`, null, {headers: headers})
        .pipe(
            tap(x => {
                sessionStorage.setItem('admin', JSON.stringify(x.admin));

                this.admin.next(x.admin);
            })
        )
}

logout(): void {
    sessionStorage.removeItem('admin');
    this.admin.next(false);
}

然后app.component.ts订阅:

private subscription: Subscription;

ngOnInit(): void {
    this.subscription = this.producerService.admin$.subscribe(x => {
        console.info(`Admin being set to ${x}`);
        this.showAdminSection = x;
    });
}

ngOnDestroy(): void {
    if (this.subscription) {
        this.subscription.unsubscribe();
    }
}

我看到的是,当我登录订阅时,会使用一个值调用该方法,但是当我调用该logout()方法时,即使我正在发送false更新,该消息也永远不会打印到控制台,说明它被设置为false. 就像只发出第一个值,然后订阅由于某种原因关闭。

我不确定为什么false似乎没有被发送/接收。

标签: angularangular7rxjs6behaviorsubject

解决方案


ngOnDestroy在从 observable 获取最新值之前调用不一定正确。

这取决于执行操作所需的逻辑或时间。在您的情况下,logout需要更多时间,并且在它完成之前ngOnDestroy被调用并且您的订阅被销毁。

例如,考虑stackblitz上的代码。如果您在test.service.ts文件中看到,我创建了 2 个函数,如下所示:

...
  nextValueDelayed(value: boolean) {
    setTimeout(() => {
      this._test.next(value);
    });
  }

  nextValue(value: boolean) {
    this._test.next(value);
  }
...

现在,从app.component.ts,我调用如下相同的:

...
  reverse() {
    this.visible = !this.visible;
    this._testService.nextValue(this.visible);
  }

  reverseDelayed() {
    this.visible = !this.visible;
    this._testService.nextValueDelayed(this.visible);
  }
...

这两个函数都是从按钮调用的,visible负责创建和销毁HelloComponent. app.component.html

<hello name="{{ name }}" *ngIf="visible"></hello>
<button (click)="reverse()">Reverse</button>
<button (click)="reverseDelayed()">Reverse Delayed</button>

现在,HelloComponent正在订阅和安慰价值并在销毁时取消订阅,如下所示: hello.component.ts

...
ngOnInit(){
    this.sub = this._testService.test$.subscribe(value=>{
      console.log(value);
    })
  }

  ngOnDestroy(){
    this.sub.unsubscribe();
  }
...

现在,尝试单击ReverseReverse Delayed按钮,您会看到,当您单击 时Reverse,它将打印所有值。但是,当您单击 时Reverse Delayed,组件将在获取最新值之前被销毁,因为我们习惯于setTimeout添加一些延迟。


推荐阅读