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
我怀疑这是因为您正在使用 BehaviourSubject。 BehaviorSubject 具有存储“当前”值的特性。这意味着您始终可以直接从 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);
});
我正在创建一个 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
我怀疑这是因为您正在使用 BehaviourSubject。 BehaviorSubject 具有存储“当前”值的特性。这意味着您始终可以直接从 BehaviorSubject.
中获取最后发出的值您使用 public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);
用 null 值初始化它后,当您对其调用 subscribe 时,它会立即发出最后一个值。在你的情况下它是 null 这就是你在 this.loggedInUser.next(user)
.
解决方案
如果您不打算获取最后存储的值,则使用 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);
});