Angular 7 - Использование BehaviorSubject для публикации результатов API для всех компонентов - PullRequest
0 голосов
/ 30 октября 2019

У меня есть вызов API, который возвращает данные о текущем пользователе (например, имя пользователя, полное имя, членство в группе авторизации, адрес электронной почты и т. Д.). Я хотел бы вызывать этот API только один раз за пользовательскую сессию, и его данные распределяются между всеми компонентами.

Я не хочу полагаться на localStorage, поскольку я не хочу, чтобы эти данные могли изменяться пользователем. Я пытаюсь использовать BehaviorSubject и пытался следовать ряду примеров, но я продолжаю получать начальное значение (ноль), когда пытаюсь получить к нему доступ через мои компоненты.

// HTTP Service:
getUserData() {
  const url = `${baseUrl}/api/users/`;
  return this.httpClient.get<UserData>(url).toPromise();
}
// Utils Service
export class UtilsService {
  private userDataSubject: BehaviorSubject<UserData>;

  constructor(
    private httpService: HttpService,
  ) {
    this.userDataSubject = new BehaviorSubject<UserData>(null);
    this.setUserData();
  }

  async setUserData() {
    let userData: UserData = await this.httpService.getUserData();
    this.userDataSubject.next(userData);
    console.log(this.userDataSubject.value); // Properly returns the data I want     
  }

  public get userDataValue(): UserData {
    return this.userDataSubject.value;
  }
// Component
  ngOnInit() {
    this.userData = this.utils.userDataValue; // This is the variable I need to set in my component.
    console.log(this.userData);               // Returns null
    console.log(this.utils.userDataValue);    // Also returns null
  }

Я также попытался использовать асинхронную функцию для userDataValue ():

async userDataValue(): Promise<UserData> {
    return this.userDataSubject.value;
  }

и изменил свой компонент:

async ngOnInit() {
    this.userData = await this.utils.userDataValue();
    console.log(this.userData);                    // Still returns null
    console.log(await this.utils.userDataValue()); // Still returns null
  }

Пока что я могу сделать эту работу, только если я не буду использоватьBehaviorSubject и вызов API в каждом компоненте, но, похоже, в этом нет необходимости. Я был бы очень признателен за любые рекомендации, как я могу сделать эту работу. Спасибо.

1 Ответ

2 голосов
/ 30 октября 2019

Проблема в том, что setUserData() является асинхронной функцией, и this.httpService.getUserData() требуется некоторое время для получения ваших данных из бэкэнда. Поэтому, когда ваш компонент вызывает его, ngOnInit() метод userDataSubject еще не получил новое значение, и поэтому он возвращает ноль. Я бы предложил использовать обработчик BehaviorSubject subscribe, чтобы ваш код делал то, что он должен делать в нужное время. Это будет что-то вроде:

export class UtilsService {
  public userDataSubject: BehaviorSubject<UserData>;

  constructor(private httpService: HttpService) {
    this.userDataSubject = new BehaviorSubject<UserData>(null);
    this.setUserData();
  }

  async setUserData() {
    let userData: UserData = await this.httpService.getUserData();
    this.userDataSubject.next(userData);     
  }

и в вашем компоненте

ngOnInit() {
  this.utils.userDataSubject.subscribe((data) => {
    if(data === null)
      return;

    console.log(data);

     // component logic to use your data
     // this will be called every time userDataSubject receives a new value
  });
}
...