Как мне получить значение в BehaviorSubject для возврата в getter?

#javascript #angular #ionic-framework #rxjs

#javascript #angular #ionic-framework #rxjs

Вопрос:

Насколько я понимаю, когда вы подписываетесь на BehaviorSubject, эта подписка является асинхронной. Я пытаюсь получить значение из объекта в BehaviorSubject и вернуть это значение в getter. Получателю необходимо вернуть тип ‘number’. Как мне подойти к этому?

Ниже у меня есть идентификатор пользователя getter, который должен возвращать идентификатор пользователя из объекта, хранящегося в BehaviorSubject _loggedInUser

 export class AuthServiceService {

  private _loggedInUser: BehaviorSubject<LoggedInUserData> = new BehaviorSubject(null);

  constructor(
    private http: HttpClient, 
    private storage: Storage
  ) { }


 /// This method below!!! --------------

  public get userId(): number{

    this._loggedInUser.pipe(
      take(1), 
      map(((loggedInUserData: LoggedInUserData) => {
        if(loggedInUserData){
          return loggedInUserData.user_id
        }
        return null;
      }))
    ).subscribe((userId: number | null) => {
      return userId;
    });
    
  }
  
 //// -----------------


  public doLogin(loginData: LoginFormData): Observable<any>{

    return this.http.post<LoggedInUserData>(`${authURL}/token`, loginData)
    .pipe(
      catchError(err => {

        if(err.status amp;amp; err.status === 403)
          return throwError('The credentials you have entered are invalid or do not exist.');
        else
          return throwError('There was an issue processing your request.');

      }), 
      tap(respData => {

        console.log('LOGGED IN USER DATA: ', respData);

        this._loggedInUser.next(respData);
        this.storage.set('userData', respData);

      })
    );



  }


  public async autoLogin(){



  }


  public doLogout(){




  }





}  

Комментарии:

1. Вы пробовали _loggedInUser.value.user_id ? Экземпляр BehaviorSubject имеет value свойство, которое присваивает самое последнее значение. rxjs-dev.firebaseapp.com/api/index/class/BehaviorSubject

2. В этом случае, должен ли я вообще использовать BehaviorSubject для хранения пользовательских данных?

3. У BehaviorSubject есть цель. Если вам это не нужно, не используйте его. Вы можете создавать различные наблюдаемые в соответствии с вашими потребностями.

4. «должен ли я вообще использовать BehaviorSubject для хранения пользовательских данных?» это было бы полезно, если вам нужно, чтобы данные были доступны в ваших компонентах

5. Ваши пользовательские данные загружаются асинхронно, поэтому вы должны спросить себя: если кто-то хочет получить доступ к userId() , а данных пока нет, было бы нормально, если бы этот кто-то получил null при userId() вызове, даже если через 5 мс присутствует идентификатор пользователя? Мы используем наблюдаемые, когда хотим получить доступ к данным, и если их нет, ждем, пока они не появятся, или реагируем на изменение данных. Работа с наблюдаемыми значениями означает возврат наблюдаемых значений из множества функций и подписку только тогда, когда нам нужны фактические данные. В большинстве случаев вы хотели бы userId() вернуть наблюдаемое.

Ответ №1:

Имея доступ к объекту, вы можете получить его значение синхронно через getValue() mothod, следующим образом:

 public get userId(): number {
  return this._loggedInUser.getValue()?.userId
}
  

Ответ №2:

Если вам просто нужен синхронный результат, вам следует использовать пример, предоставленный Рафи Хенигом:

     public get userId(): number {
      return this._loggedInUser.getValue()?.userId
    }
  

Если вы хотите, чтобы оно было асинхронным, вы могли бы вместо этого вернуть Observable<number> и использовать асинхронный канал в вашем html, если вам нужно показать его там. Если нет, вы можете подписаться на это наблюдаемое, где вам это нужно, или сохранить подписку, если вы хотите отслеживать изменения значения. Я не уверен, что это то, что вы хотите, но вот пример этого:

   public get userId(): Observable<number> {
    return this._loggedInUser.pipe(
      map((item) => item?.userId)
    );
  }
  

Для HTML используйте: {{ userId | async }} а для кода typescript вы можете использовать:

     this.userId.pipe(take(1)).subscribe((userId) => {
      console.log(userId);
    });
  

Если вы хотите отслеживать изменения в вашем typescript, вам следует удалить take(1) и просто subscribe его. Не забудьте очистить подписку в ngOnDestroy .

Комментарии:

1. выщипывание вместо map this._loggedInUser.pipe(pluck('userId')) имело бы больше смысла

2. @Stavm pluck устареет в версии 7 и будет удален в версии 8, так что использование map неплохо.

Ответ №3:

Другой подход — преобразовать Observable в Promise, затем использовать async / await:

 const user = await this._loggedInUser.toPromise();
return user amp;amp; user.userId;
  

Комментарии:

1. Хотя, я не думаю, что у вас может быть асинхронный getter.

2. да, пропустил это. В любом случае, согласно большому количеству кода внутри getter, на мой взгляд, было бы лучше преобразовать его в метод … но решать вам :-). Вместо этого используйте GetValue().