Angular中如何统一封装结合AngularFire与MongoDB的认证Observable?
问题根源
你当前的写法无法生效的核心原因是:组件订阅的是服务初始化时of(null)生成的旧Observable实例,后续你直接给_mongoUser赋新的HttpClient返回的Observable实例,旧的订阅不会关联到新实例,自然收不到用户数据更新。
正确实现方案
推荐使用BehaviorSubject来存储用户状态,它可以缓存最新值,新订阅的组件也能立刻拿到当前的用户数据,同时遵循RxJS流的最佳实践,避免嵌套订阅。
第一步:调整服务导入
补充需要的RxJS依赖:
import { Observable, of, BehaviorSubject, switchMap, from, tap, catchError } from 'rxjs';
第二步:修改服务属性定义
封装内部状态,只对外暴露只读的Observable:
@Injectable({ providedIn: 'root' }) export class AuthService { public redirectRoute = '' public loginError = ''; // 私有Subject,用于更新/存储用户状态,初始值为null private readonly _mongoUserSub = new BehaviorSubject<User | null>(null); // 公开只读Observable,供所有组件订阅消费 public readonly mongoUser$ = this._mongoUserSub.asObservable(); // 可选:同步获取当前用户数据的快捷方法 public get currentMongoUser(): User | null { return this._mongoUserSub.value; } constructor(public auth: AngularFireAuth, private router: Router, private http: HttpClient,) { // 用RxJS操作符串联流,避免嵌套订阅 this.auth.user.pipe( switchMap(firebaseUser => { // 未登录直接返回null if (!firebaseUser) return of(null); // 将获取token的Promise转为Observable return from(firebaseUser.getIdToken()).pipe( switchMap(idToken => { const headers = { headers: new HttpHeaders().set('idToken', idToken) }; return this.http.post<User>( `${environment.apiUrl}/users/email/${firebaseUser.email}`, { personal: { email: firebaseUser.email } }, headers ).pipe( // 可选:捕获请求错误,避免流中断 catchError(() => of(null)) ); }) ); }), // 更新用户状态到Subject tap(mongoUser => this._mongoUserSub.next(mongoUser)) ).subscribe(); } }
第三步:组件中订阅使用
直接订阅服务公开的mongoUser$即可:
constructor(private authService: AuthService) { this.authService.mongoUser$.subscribe(val => { if (val) { this.editForm.patchValue({ 'username': val.username }) } }) }
推荐配合Angular的async管道在模板中使用,不需要手动取消订阅,可避免内存泄漏:
<div *ngIf="authService.mongoUser$ | async as user"> <p>当前登录用户:{{ user.username }}</p> </div>
内容的提问来源于stack exchange,提问作者Marcus Gallegos
相关产品推荐
相关产品推荐

