首页 > 解决方案 > Angular - 页面重新加载后,来自 sharedService 的 BehaviorSubject 在组件中为空

问题描述

我正在创建一个 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()方法来获取用户。正确接收了用户 ID 和用户数据,但是在从setLoggedInUser调用this.loggedInUser.next(user)之前调用了组件中的ngOnInit方法。这就是我在组件中收到null的原因。

我还尝试从我的app.component调用setLoggedInUser() ,而不是从UserService的构造函数调用它:

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 传递,如此处提到的: Behavior subject value is empty when trying to fetch from a second component

标签: angularbehaviorsubject

解决方案


我怀疑它正在发生,因为您正在使用BehaviourSubjectBehaviorSubject 具有存储“当前”值的特性。这意味着您始终可以直接从 BehaviorSubject 获取最后发出的值

你初始化服务public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);

用空值初始化它后,当你调用时,它会立即发出最后一个值。在您的情况下,它是null,这就是您在之前收到 emit 的原因this.loggedInUser.next(user)

解决方案

如果您的意图不是获取最后存储的值,则使用主题(而不是使用BehaviourSubject )。

或者

我不确定,但是使用BehaviourSubject,您可以将behaviorSubject构造函数保持为而不是null并检查它是否给您预期的结果。


推荐阅读