使用RxJS处理异步数据:登录后其他组件无法获取用户数据
问题:登录后其他组件无法获取用户数据,服务内却能正常获取
场景说明
我有一个loginComponent,接收邮箱和密码并发起HTTP请求获取用户数据,希望通过服务在其他组件中使用该用户数据。但登录后,需要使用用户数据的组件中得到的是null,服务中更新数据的方法里却能获取到用户数据。
登录组件代码
onRecievingResults(value:loginInterface){ this.authService.saveData(value); } onLog(){ this.onRecievingResults(this.loginUser) this.router.navigateByUrl('/stats/list') }
服务代码
public currentUser:User | null = null; private dataUserSource = new BehaviorSubject<User | null>(this.currentUser); dataEmitter = this.dataUserSource.asObservable(); public saveData(value:loginInterface){ this.loginUser(value).subscribe() this.dataUserSource.next(this.currentUser); } public loginUser(loginInterface: loginInterface | null){ const url = `${this.basicURL}/login` const body = {email: loginInterface?.email, password1: loginInterface?.password1} return this.http.post<loginResponse>(url, body) .pipe( map(({user, token}) => this.setAuthentication(token, user)), catchError(err => throwError(() => err.error.message)) ) } private setAuthentication( token:string, user: User){ this.currentState = authStatus.Authenticated this.currentUser = user localStorage.setItem('token', token) console.log(this.currentUser) //<-- 此处能获取到用户数据 return true }
其他组件代码
ngOnInit(): void { this.authService.dataEmitter.subscribe(data => console.log(data)) } public currentUser:User | null = null
问题原因
核心问题是异步操作的执行顺序:
this.loginUser(value).subscribe()是异步HTTP请求,调用后会立即执行后续代码,不会等待请求完成。- 所以
this.dataUserSource.next(this.currentUser)会在HTTP请求返回、setAuthentication更新currentUser之前执行,此时currentUser还是初始的null。
解决方法
需要在HTTP请求成功完成后,再发送BehaviorSubject的更新通知,修改服务中的saveData方法:
public saveData(value:loginInterface){ this.loginUser(value).subscribe({ next: () => { // 请求成功后,currentUser已被setAuthentication更新,此时再发送通知 this.dataUserSource.next(this.currentUser); }, error: (err) => { // 处理登录失败的情况 console.error('登录失败:', err); } }); }
也可以优化loginUser方法,让它直接返回用户数据,再在saveData中更新Subject,逻辑更清晰:
public loginUser(loginInterface: loginInterface | null){ const url = `${this.basicURL}/login` const body = {email: loginInterface?.email, password1: loginInterface?.password1} return this.http.post<loginResponse>(url, body) .pipe( map(({user, token}) => { this.setAuthentication(token, user); return user; // 返回用户数据 }), catchError(err => throwError(() => err.error.message)) ) } public saveData(value:loginInterface){ this.loginUser(value).subscribe({ next: (user) => { this.dataUserSource.next(user); // 直接用返回的user更新 }, error: (err) => { console.error('登录失败:', err); } }); }
内容的提问来源于stack exchange,提问作者Bayes-T
相关产品推荐
相关产品推荐

