Угловой - BehaviorSubject из sharedService пуст в компоненте после перезагрузки страницы

Я создаю приложение Angular 9. У меня есть общая служба, которую я использую для обмена пользовательскими данными между моими компонентами. Он работает правильно, пока я не перезагружу приложение.

Моя sharedService называется UserService. Сервис устанавливает значение BehaviorSubject. При входе в систему он вызывает метод setLoggedInUser () для получения идентификатора пользователя из JWT, который хранится в другом BehaviorSubject в AuthenticationService. Затем данные пользователя запрашиваются через HTTP-вызов. Установлено значение loggedInUser:

export class UserService {

  public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);

  constructor(private http: HttpClient, private authenticationService: AuthenticationService) {
    this.setLoggedInUser();
  }

  async setLoggedInUser() {
    const userID: string = await this.authenticationService.userID.pipe(take(1)).toPromise();
    const user: User = await this.getUserByID(userID).pipe(take(1)).toPromise();
    this.loggedInUser.next(user);
  }

  getUserByID(id: string): Observable<User> {
    return this.http.get<User>(`${this.baseUrl}/${id}`);
  }
}

В моем компоненте я вызываю пользовательские данные при инициализации:

ngOnInit() {
   this.userService.loggedInUser.pipe(take(1)).subscribe(user => {
    console.log(user);
   });
}

При перезагрузке конструктор UserService вызывает метод setLoggedInUser () для получения пользователя. UserID и пользовательские данные получены правильно, но метод ngOnInit из компонента вызывается до того, как this.loggedInUser.next (user) вызывается из setLoggedInUser < / em>. Вот почему я получаю null в своем компоненте.

Я также попытался вызвать setLoggedInUser () из моего app.component вместо вызова его из конструктора UserService:

export class AppComponent implements OnInit {

  constructor(private userService: UserService) { }

  async ngOnInit() {
    await this.userService.setLoggedInUser();
    const user = await this.UserService.loggedInUser.toPromise();
    console.log(user);
  }

}

Но это также показывает мне null. Это все та же проблема, что и раньше.

Другой метод, который я пробовал без эффекта, - передать BehaviourSubject как Observable, как указано здесь: Значение субъекта поведения пусто при попытке получить из второго компонента


person Xleg    schedule 31.07.2020    source источник


Ответы (2)


Похоже, вы хотите получить одно значение из loggedInUser (таким образом, вы используете take(1)), но когда вы перезагружаете приложение, первое значение, которое вы получаете, - это то, которое вы используете для инициализации BehaviorSubject.

Чтобы дождаться определения пользователя перед его получением, вы можете добавить оператор filter следующим образом:

this.userService.loggedInUser
  .pipe(
    filter(user => user !== null),
    take(1)
  ).subscribe(user => {
    console.log(user);
   });
person Cédric Rémond    schedule 31.07.2020
comment
Это работает. Может быть, это может раздражать выполнение нулевой проверки, но для моих целей это нормально. - person Xleg; 31.07.2020

Я подозреваю, что это происходит из-за того, что вы используете BehaviourSubject. BehaviorSubject имеет свойство хранить «текущее» значение. Это означает, что вы всегда можете напрямую получить последнее переданное значение из BehaviorSubject.

Вы инициализируете службу с помощью public loggedInUser: BehaviorSubject<User> = new BehaviorSubject<User>(null);

После инициализации его значением null, когда вы вызываете для него subscribe, он немедленно выдаст последнее значение. В вашем случае это null, и поэтому вы получаете emit до this.loggedInUser.next(user).

Решение

Вы используете тему (вместо BehaviourSubject), если вы не намерены получать последнее сохраненное значение.

ИЛИ

Я не уверен, но с помощью BehaviourSubject вы можете оставить конструктор behaviorSubject пустым вместо null и проверить, дает ожидаемый результат.

person micronyks    schedule 31.07.2020
comment
BehaviorSubject будет по-прежнему генерировать, когда кто-то подписывается на него, и он всегда должен иметь начальное значение - person StPaulis; 31.07.2020
comment
да, но в этом случае выдаваемое значение будет пустым. не так ли? Итак, я предложил использовать Subject. - person micronyks; 31.07.2020
comment
Я не могу оставить BehaviourSubject пустым, он должен содержать значение. С помощью Тема печатается пользовательское значение. Но у меня две проблемы. Сначала, когда я выполняю несколько вызовов Subject, он останавливается на втором вызове, и остальная часть кода не выполняется. Пример: const user = await this.userService.loggedInUser.pipe (take (1)). ToPromise (); Но я решил это, создав переменную, которая используется во всем компоненте. Вторая проблема в том, что теперь он работает только при перезагрузке. Когда я вхожу в систему, метод входа в систему вызывает setLoggedInUser, и я перехожу к своему компоненту, ничего не происходит. Ничего не регистрируется. - person Xleg; 31.07.2020