Angular - 页面重新加载后,来自 sharedService 的 BehaviorSubject 在组件中为空

Angular - BehaviorSubject from sharedService is empty in Component after page reload

我正在创建一个 Angular 9 应用程序。我有一个共享服务,我用它来在我的组件之间共享用户数据。在我重新加载应用程序之前,它工作正常。

我的 sharedService 叫做 UserService。该服务设置 BehaviorSubject 的值。登录时,它调用方法 setLoggedInUser() 从 JWT 获取用户 ID,该用户 ID 存储在 AuthenticationService 的另一个 BehaviorSubject 中。然后通过 HTTP 调用请求用户的数据。该值设置为 loggedInUser:

export class UserService {

  public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);

  constructor(private http: HttpClient, private authenticationService: AuthenticationService) {
    this.setLoggedInUser();
  }

  async setLoggedInUser() {
    const userID: string = await this.authenticationService.userID.pipe(take(1)).toPromise();
    const user: User = await this.getUserByID(userID).pipe(take(1)).toPromise();
    this.loggedInUser.next(user);
  }

  getUserByID(id: string): Observable<User> {
    return this.http.get<User>(`${this.baseUrl}/${id}`);
  }
}

在我的组件中,我在 init 上调用用户数据:

ngOnInit() {
   this.userService.loggedInUser.pipe(take(1)).subscribe(user => {
    console.log(user);
   });
}

重新加载时,UserService 的构造函数调用 setLoggedInUser() 方法来获取用户。正确接收了 userID 和用户数据,但是在调用 this.loggedInUser.next(user) 之前调用了组件中的 ngOnInit 方法来自 setLoggedInUser。这就是我在组件中收到 null 的原因。

我还尝试从 app.component 调用 setLoggedInUser() 而不是从 用户服务:

export class AppComponent implements OnInit {

  constructor(private userService: UserService) { }

  async ngOnInit() {
    await this.userService.setLoggedInUser();
    const user = await this.UserService.loggedInUser.toPromise();
    console.log(user);
  }

}

但这也向我展示了 null。还是和之前一样的问题

另一种我尝试但没有效果的方法是将 BehaviourSubject 作为 Observable 传递,如下所述: Behaviour subject value is empty when trying to fetch from a second component

我怀疑这是因为您正在使用 BehaviourSubjectBehaviorSubject 具有存储“当前”值的特性。这意味着您始终可以直接从 BehaviorSubject.

中获取最后发出的值

您使用 public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);

初始化服务

null 值初始化它后,当您对其调用 subscribe 时,它会立即发出最后一个值。在你的情况下它是 null 这就是你在 this.loggedInUser.next(user).

之前收到 emit 的原因

解决方案

如果您不打算获取最后存储的值,则使用 subject(而不是使用 BehaviourSubject)。

我不确定,但是使用 BehaviourSubject,你可以保留 behaviourSubject 构造函数 empty而不是 null 并检查它是否给你预期的结果。

似乎您想从 loggedInUser 中获取一个值(因此您使用 take(1)),但是当您重新加载应用程序时,您获取的第一个值是用于初始化BehaviorSubject.

要等到用户被定义后再获取它,您可以像这样添加一个 filter 运算符:

this.userService.loggedInUser
  .pipe(
    filter(user => user !== null),
    take(1)
  ).subscribe(user => {
    console.log(user);
   });