AngularFireAuth在路由更改时清除用户状态

AngularFireAuth在路由更改时清除用户状态,angular,authentication,observable,Angular,Authentication,Observable,在我对可观察物、AngularFireAuth和firebase身份验证的理解中,我似乎遇到了困难。下面是我的身份验证服务的一个片段 export class AuthService { user$: Observable<firebase.User>; constructor( private db: AngularFirestore, private fireAuth: AngularFireAuth, ) { this.us

在我对可观察物、AngularFireAuth和firebase身份验证的理解中,我似乎遇到了困难。下面是我的身份验证服务的一个片段

export class AuthService {


user$: Observable<firebase.User>;

  constructor(
      private db: AngularFirestore,
      private fireAuth: AngularFireAuth,
      ) { 

  this.user$ = fireAuth.authState.pipe(
    switchMap(user => {
      if (user) {
        return this.db.doc<User>(`users/${user.uid}`).valueChanges();
      } else {
        return of(null);
      };
    })
   );

}
我尝试在authService和组件中创建方法来检索和提取数据,要么在第一页加载时有效,要么仅在从路由更改返回时有效

我确实尝试过将auth服务中的代码更改为change take(1),这使得订单可以正常工作。路由更改后和登录时。但是,标头组件停止工作,用户信息在登录时不会更改

user$: Observable<firebase.User>;

  constructor(
      private db: AngularFirestore,
      private fireAuth: AngularFireAuth,
      ) { 

  this.user$ = fireAuth.authState.pipe(
take(1),
switchMap(user => {
  if (user) {
    return this.db.doc<User>(`users/${user.uid}`).valueChanges();
  } else {
    return of(null);
  };
})


 );
user$:可观察;
建造师(
私人数据库:AngularFirestore,
私人消防员:AngularFireAuth,
) { 
this.user$=fireAuth.authState.pipe(
以(1)为例,
开关映射(用户=>{
如果(用户){
返回这个.db.doc(`users/${user.uid}`)。valueChanges();
}否则{
返回(空);
};
})
);

除此之外,您的代码片段看起来非常完美

您在两个组件中使用
user$
订阅:页眉和签出。页眉组件在所有情况下都可以正常工作,因为无论您的路线如何,该组件始终位于页面顶部(我根据您的问题假设)。但只有当您导航到该页面时,才会显示签出组件。有趣的是,
user$
obseravble会在用户登录时立即发送用户的详细信息,而在此期间,签出组件甚至不会显示,因此不会创建该组件,也不会显示订阅了
user$
observable。
user$
在创建签出组件并订阅它时不会重播最后一个值。因此,您在此处看不到登录用户的详细信息

因此,您必须使用来捕获已登录用户的详细信息。这里使用ReplaySubject的主要原因是它可以将一些旧的发出值重放到新订户。下面让我们看看如何做到这一点

AuthService

// ...
import { ReplaySubject } from 'rxjs';
// ...

export class AuthService {
  // Create a ReplaySubject to store the history of logged in users
  private loggedInUsersSubject = new ReplaySubject<firebase.User>(1);

  // user$ is now returns an obseravble for the history subject
  get user$(): Observable<firebase.User> {
    return this.loggedInUsersSubject.asObservable();
  }

  constructor(
    private db: AngularFirestore,
    private fireAuth: AngularFireAuth,
  ) {
    // do not store the fireAuth observable in user$
    // Instead push new logged in users to the ReplaySubject
    fireAuth.authState.pipe(
      switchMap(user => {
        if (user) {
          return this.db.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
          return of(null);
        };
      })
    ).subscribe(user => {
      // console.log(user);
      // Push the details of logged in user to ReplaySubject
      this.loggedInUsersSubject.next(user);
    });
}
/。。。
从“rxjs”导入{ReplaySubject};
// ...
导出类身份验证服务{
//创建ReplaySubject以存储登录用户的历史记录
private loggedInUsersSubject=新的ReplaySubject(1);
//用户$is现在返回历史主题的obseravble
获取用户$():可观察{
返回此.loggedinUsersObject.asObservable();
}
建造师(
私人数据库:AngularFirestore,
私人消防员:AngularFireAuth,
) {
//不要将fireAuth可见存储在用户中$
//而是将新登录的用户推送到ReplaySubject
fireAuth.authState.pipe(
开关映射(用户=>{
如果(用户){
返回这个.db.doc(`users/${user.uid}`)。valueChanges();
}否则{
返回(空);
};
})
).subscribe(用户=>{
//console.log(用户);
//将登录用户的详细信息推送到ReplaySubject
this.loggedinUsersObject.next(用户);
});
}
如上面的代码片段所示,我们正在使用缓冲区大小为1的Replay主题,以便它可以存储最后发出的值。现在,任何新订阅者都将在订阅时获得最后发出的值

Header组件应该和以前一样工作正常,但是现在Checkouts组件还将捕获登录用户的详细信息,并在代码中不做任何更改的情况下显示它

p.S:


从Checkout组件中删除所有rxjs操作符和您所做的实验,以使上述解决方案正常工作。还可以订阅
ngOnInit()中的
user$
observable
方法在签出组件中,而不是在构造函数中。

非常感谢。我在这个问题上纠缠了几天。我尝试了replay主题,但我既没有实现缓冲区大小,也没有订阅,而是使用.next()将用户值推送到ReplaySubject。我现在对这个概念有了更好的理解。我感谢您的帮助。
constructor(
  public auth: AuthService,
  public stripePayment: PaymentService,
  private cart: CartService
  ) { 
   //this.auth.user$.subscribe( user => this.userData = user)
  }

  ngOnInit(){
    this.auth.user$.subscribe( data => console.log(data) )
    }
user$: Observable<firebase.User>;

  constructor(
      private db: AngularFirestore,
      private fireAuth: AngularFireAuth,
      ) { 

  this.user$ = fireAuth.authState.pipe(
take(1),
switchMap(user => {
  if (user) {
    return this.db.doc<User>(`users/${user.uid}`).valueChanges();
  } else {
    return of(null);
  };
})


 );
// ...
import { ReplaySubject } from 'rxjs';
// ...

export class AuthService {
  // Create a ReplaySubject to store the history of logged in users
  private loggedInUsersSubject = new ReplaySubject<firebase.User>(1);

  // user$ is now returns an obseravble for the history subject
  get user$(): Observable<firebase.User> {
    return this.loggedInUsersSubject.asObservable();
  }

  constructor(
    private db: AngularFirestore,
    private fireAuth: AngularFireAuth,
  ) {
    // do not store the fireAuth observable in user$
    // Instead push new logged in users to the ReplaySubject
    fireAuth.authState.pipe(
      switchMap(user => {
        if (user) {
          return this.db.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
          return of(null);
        };
      })
    ).subscribe(user => {
      // console.log(user);
      // Push the details of logged in user to ReplaySubject
      this.loggedInUsersSubject.next(user);
    });
}