【问题标题】:Angular - BehaviorSubject from sharedService is empty in Component after page reloadAngular - 页面重新加载后,来自 sharedService 的 BehaviorSubject 在组件中为空
【发布时间】:2020-11-21 07:53:19
【问题描述】:

我正在创建一个 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 和用户数据,但是在从 setLoggedInUserthis.loggedInUser.next(user) 之前调用了组件中的 ngOnInit 方法/em>。这就是我在组件中收到 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 传递,如此处所述: Behaviour subject value is empty when trying to fetch from a second component

【问题讨论】:

    标签: angular behaviorsubject


    【解决方案1】:

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

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

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

    【讨论】:

    • 这行得通。也许做空检查可能很烦人,但就我的目的来说没关系。
    【解决方案2】:

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

    你用public loggedInUser: BehaviorSubject&lt;User&gt; = new BehaviorSubject&lt;User&gt;(null);初始化服务

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

    解决方案

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

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

    【讨论】:

    • BehaviorSubject 仍然会在有人订阅它时发出,并且它应该总是有一个初始值
    • 是的,但在这种情况下,发出的值将为空。不是吗?而且,所以我建议使用Subject
    • 我不能保持 BehaviourSubject 为空,它必须包含一个值。使用 Subject 它打印用户值。但我有两个问题。首先,当我对 Subject 进行多次调用时,它会在第二次调用时停止,其余代码将不会被执行。示例: const user = await this.userService.loggedInUser.pipe(take(1)).toPromise();但是我通过创建一个在整个组件中使用的变量来解决它。第二个问题是,它现在只适用于重新加载。当我登录时,登录方法调用 setLoggedInUser 并且我导航到我的组件没有任何反应。没有任何记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 2014-02-12
    • 2016-05-12
    相关资源
    最近更新 更多