Angular中根据用户ID获取用户角色失败(role为undefined)求助
解决AngularFire中异步获取用户Role的问题
你猜的没错!问题确实出在异步操作的执行顺序上。咱们来拆解一下你的代码逻辑:
- 当
this.user.subscribe触发时,你先同步拿到了uid,然后调用getUserRole(this.uid)——这是一个异步的数据库请求,它不会立刻返回结果,而是要等数据库响应后才会执行subscribe里的回调函数。 - 但你在
getUserRole的subscribe外面直接打印this.role,这时候数据库请求还没完成,this.role自然还是undefined。
修复方案1:把依赖role的逻辑放在异步回调内部
最直接的方式就是把所有需要用到role的代码都放到getUserRole的subscribe回调里,确保只有当数据返回后才执行相关逻辑:
constructor( private _firebaseAuth: AngularFireAuth, private db: AngularFireDatabase, private router: Router ) { this.user = _firebaseAuth.authState; this.user.subscribe( (user) => { if (user) { this.userDetails = user; this.userEmail = this.userDetails.email; this.uid = this.userDetails.uid; this.getUserRole(this.uid).subscribe(result => { this.role = result.role; console.log('role >>>>>>>>>>>>>>', this.role); // 所有需要用到role的逻辑都放在这里!比如路由跳转、权限判断 if (this.role === 'admin') { this.router.navigate(['/admin-panel']); } else { this.router.navigate(['/user-home']); } }); console.log('uid >>>>>>>>>>>>>>', this.uid); // 这个会先打印,因为是同步执行的 } else { this.userDetails = null; } }); } getUserRole(userId: string): Observable<any> { return this.db.list('users', ref => ref.orderByChild('uid').equalTo(userId)).valueChanges() .map(result => result[0]); }
修复方案2:用RxJS操作符合并Observable(更优雅的写法)
如果不想嵌套太多subscribe,可以用RxJS的switchMap操作符,把两个异步流(authState和数据库请求)合并起来,代码结构会更整洁:
import { switchMap, map, of } from 'rxjs'; constructor( private _firebaseAuth: AngularFireAuth, private db: AngularFireDatabase, private router: Router ) { this.user = _firebaseAuth.authState.pipe( switchMap(user => { if (user) { this.userDetails = user; this.userEmail = user.email; this.uid = user.uid; // 切换到数据库请求的Observable,自动等待结果返回 return this.getUserRole(user.uid); } else { this.userDetails = null; return of(null); } }) ).subscribe(userRole => { if (userRole) { this.role = userRole.role; console.log('role >>>>>>>>>>>>>>', this.role); // 这里处理role相关逻辑 } }); } getUserRole(userId: string): Observable<any> { return this.db.list('users', ref => ref.orderByChild('uid').equalTo(userId)).valueChanges() .pipe(map(result => result[0])); }
额外提示:避免内存泄漏
如果组件会被销毁(比如路由跳转),记得手动取消订阅防止内存泄漏:
import { Subscription } from 'rxjs'; private userSubscription: Subscription; constructor(...) { this.userSubscription = this.user.subscribe(...); } ngOnDestroy() { this.userSubscription.unsubscribe(); }
或者用async管道在模板里自动管理订阅,更省心:
组件代码:
userWithRole$: Observable<any>; constructor(...) { this.userWithRole$ = this._firebaseAuth.authState.pipe( switchMap(user => { if (user) { return this.db.list('users', ref => ref.orderByChild('uid').equalTo(user.uid)).valueChanges() .pipe( map(users => ({ ...user, role: users[0]?.role })) ); } else { return of(null); } }) ); }
模板代码:
<div *ngIf="userWithRole$ | async as user"> <p>当前用户邮箱:{{ user.email }}</p> <p>用户角色:{{ user.role }}</p> </div>
这样就完全不用手动处理订阅的取消啦!
内容的提问来源于stack exchange,提问作者Elias
相关产品推荐
相关产品推荐

