SwitchMap оператор с массивом - PullRequest
2 голосов
/ 15 апреля 2019

Я пытаюсь выучить rxjs и концепцию Observable в целом, и у меня есть сценарий, в котором у меня есть класс <Room>{}, где <Player>{} может объединяться в стиле отношения многих ко многим.

В Firestore у меня есть коллекция rooms, где у каждой комнаты есть свойство с именем players, которое является массивом пользователя uid s.

Когда создается компонент комнаты, я подписываюсь на _roomService.getPlayersInRoom(roomId), который выглядит следующим образом:

getPlayersInRoom(roomId: string) {
  return this._db.doc<Room>(`rooms/${roomId}`).valueChanges().pipe(
    map(room => room.players),
    switchMap(players => players),//2
    switchMap(playerId => {
      if(playerId) {
        return this._db.doc<Player>(`users/${playerId}`).valueChanges();
      }
    })
  );
}

Я подпишусь на него позже с

.subscribe(player => {
    if (player) {
      this.players = new Array();
      this.players.push(player);
    }

Здесь есть пара вопросов. Моя наблюдаемая не возвращает массив игроков, как ожидалось (см. Строку // 2, которая преобразует строку [] в строку)

Другая проблема заключается в том, что я обновляю массив this.players в своем компоненте каждый раз, когда меняется комната (в противном случае .push() будет выдавать дубликаты.

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

1 Ответ

2 голосов
/ 15 апреля 2019

Во-первых, switchMap ожидает, что вы вернете наблюдаемое.Если это значение, похожее на массив - оно превратит его в массив, используя from (см. Этот пример from ).

Если вы действительно хотите вернуть массив обратнопоток - вы должны вернуть поток, например, используя of: switchMap(value => of([]))

Тем не менее, в вашем случае вы хотите заменить каждый идентификатор в массиве потоком.Например, нам понадобится оператор combineLatest (название говорит само за себя).Каждый массив игроков мы будем переключать на новый поток.В этом новом потоке мы объединяем последние значения в valueChanges() потоках.

Вот пример:

getPlayersInRoom(roomId: string) {
    return this._db.doc<Room>(`rooms/${roomId}`).valueChanges().pipe(
      map(room => room.players),
      switchMap(players => {
        // turn array of player IDs
        // into array of streams of changes
        const playersStreams = players.map(
          playerId => this._db.doc<Player>(`users/${playerId}`).valueChanges()
        );

        // combine latest changes from all streams in that array
        return combineLatest(...playersStreams);
      })
    );
  }

Тогда в подписке players будет массив объединенных значений изvalueChanges().

getPlayersInRoom(5)
  .subscribe(players => {
    this.players = players;
  })

Обратите внимание, что существует несколько способов объединения значений из нескольких valueChanges().Наиболее распространенными являются: forkJoin и zip

И есть еще методы для отображения значения в потоке

Надеюсь, это поможет

...