Очистка состояния пользователя AngularFireAuth при изменении маршрута - PullRequest
0 голосов
/ 01 марта 2020

кажется, что я ударил стену, когда в моем понимании наблюдаемых, 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);
      };
    })
   );

}

Это хорошо работает для меня с моими методами входа в систему и выхода из системы, которые у меня есть в шапке. Я могу подписаться на канал asyn c и отобразить кнопку входа в систему, если пользователь вышел из системы, и некоторую информацию о пользователе, если вошли в систему.

Header.component. html

<div *ngIf='!(auth.user$ | async )'>
    <button 
        class="login"
        (click)="openModal()"
        > 
        Login
    </button>
</div>
<div *ngIf='auth.user$ | async as user'>
    <h3>Welcome, {{ firstName( user.displayName) }}! </h3>
    <img [src]='user.photoURL' 
         class='profile'
         *ngIf='user.photoURL'>
    <button (click)="auth.signOut()">Logout</button>
</div>

Теперь в своей кассе я создал форму доставки, которую я хочу показать только в том случае, если пользователь вошел в систему. Я также планировал извлечь идентификатор клиента с полосой из firebase, чтобы добавить его в свой объект orderData. Все работало отлично, пока я не сменил маршруты на страницу продукта и не вернулся к оформлению заказа. Когда я делаю это, пользователь выходит из системы, форма исчезает, а stripeId из пользовательской подписки $ исчезает. У меня такой же логин c в моей кассе, как и в моем заголовке.

Checkout.component. html

<div *ngIf="!(auth.user$ | async)">Please register</div>

<form [formGroup]='orderForm' *ngIf="auth.user$ | async">...</form>

В моем компоненте кассы я подписан на пользователя $ и консоль записывают значение в ngOnInit (). Когда я делаю это, на странице refre sh печатаются два значения, а когда я меняю маршруты и возвращаю, ничего не печатается.

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) )
    }

Я пытался создать методы в authService и компоненте для извлечения и извлечения данных, и он либо работает при загрузке первой страницы, либо только при возврате из изменения маршрута.

Я попытался изменить свой код в службе аутентификации, чтобы изменить 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);
  };
})


 );

1 Ответ

0 голосов
/ 01 марта 2020

Ваш фрагмент кода выглядит идеально, за исключением этого.

Вы используете подписку user$ на 2 компонента: заголовок и извлечение. Компонент «Заголовок» будет работать нормально во всех случаях, поскольку компонент всегда будет находиться вверху вашей страницы, независимо от маршрута, по которому вы находитесь (мое предположение из вашего вопроса). Но компонент Checkouts будет отображаться только при переходе на эту страницу. Здесь возникает интересная часть: user$ obseravble отправил бы данные пользователя, как только он / она войдет в систему, и в течение этого времени компонент Checkouts даже не отображается, и, следовательно, компонент не будет создан, и он не будет т подписался на user$ наблюдаемый. user$ не будет воспроизводить последнее значение при создании компонента Checkouts и подписку на него. Следовательно, вы не видите здесь информации о вошедшем в систему пользователе.

Таким образом, вы должны использовать ReplaySubject , чтобы получить информацию о вошедшем в систему пользователе. Основная причина использования 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);
    });
}

Как показано в приведенном выше фрагменте кода, мы используем тему воспроизведения с размером буфера: 1, чтобы он мог хранить последнее переданное значение. Теперь все новые подписчики получат последнее значение в подписке.

Компонент заголовка должен работать как и прежде. Но теперь компонент Checkouts также будет собирать сведения о зарегистрированном пользователе и отображать его без каких-либо изменений в коде.

PS:

Удалить все rx js операторы и эксперименты, которые вы провели из компонента Checkouts, чтобы вышеуказанное решение работало. Также подпишитесь на user$, наблюдаемый в методе ngOnInit() в компоненте Checkouts, а не в конструкторе.

...