#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/BehaviorSubject2. В этом случае, должен ли я вообще использовать 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().