Оператор совместного использования с вложенными наблюдаемыми

#angular #rxjs #ngxs

#угловой #rxjs #ngxs

Вопрос:

Я создаю игровой модуль, который отвечает за загрузку игрока buildings , а затем модифицирует выбранные объекты в расширенный класс зданий, содержащий дополнительное поле — Оставшееся время, информирующее, сколько секунд осталось до завершения обновления lvl зданий (это поле обновляется каждую секунду).

buildings -> buildingsWithDiff -> buildingsWithTimer

  1. Загрузка buildings
  2. Сопоставьте buildings buildingsWithDiff , чтобы узнать разницу между датой начала таймера и датой окончания обновления
  3. Сопоставление buildingsWithDiff , в buildingsWithTimer которое вычитается количество тиков из результирующей разницы
 class Building {
  name: string;
  lvl: number;
  endDate: Date; // date of upgrading of the building
}

class BuildingWithDiff extends Building {
  diffTime: number; // difference of seconds between the currentDate and the endDate;
}

class BuildingWithTimer extends BuildingWithDiff {
  remainingTime: number; // seconds left to complete upgrading a building
}

/* ------------- */

const getBuildings$ = (store: Store): Observable<Building[]> => {
  const buildings$: Observable<Building[]> = store.select(
    (appState: AppState) => appState.buildings
  ); // source
  return buildings$;
};

const getBuildingsWithTimers$ = (
  store: Store
): Observable<BuildingWithTimer[]> => {
  const buildings$: Observable<Building[]> = getBuildings$(store);

  const buildingsWithDiff$: Observable<BuildingWithDiff[]> = buildings$.pipe(
    map((buildings) =>
      buildings.map((building) => {
        const currentDate: Date = new Date();
        const diffTime: number =
          Math.ceil(
            building.endDate.getTime() - currentDate.getTime()
          ) / 1000;

        return {
          ...building,
          diffTime,
        };
      })
    )
  );

  const buildingsWithTimer$: Observable<BuildingWithTimer[]> = buildingsWithDiff$.pipe(
    switchMap((buildingsWithDiff) =>
      timer(0, 1000).pipe(
        map((tick: number) =>
          buildingsWithDiff.map((buildingWithDiff) => {
            const remainingTime: number = buildingWithDiff.diffTime - tick;

            return {
              ...buildingWithDiff,
              remainingTime,
            };
          })
        )
      ),
      // share()? - it doesn't work :(
    )
  );

  return buildingsWithTimer$;
};
  

Многоадресная рассылка вложенных таймеров — как это сделать?

Подписка на селектор выше генерирует ошибки, потому что есть несколько наблюдателей, и не все из них выполняются одновременно. Добавление share оператора не работает. В чем может быть проблема?

Есть два места, где это подписано:

  • trigger — функция, которая вызывается в ngxsOnInit (ожидает remainingTime <= 0 отправки соответствующего действия)
  • building component — угловой компонент, который отображает оставшееся время

Приложение работает нормально, когда я включаю его на подстранице, где существует этот компонент — оба наблюдателя отображают одинаковое значение тика в таймере.

Проблема заключается в том, что когда я выхожу из подстраницы, на которой находился компонент, потому trigger что он работает все время, и тики все еще подсчитываются, но компонент завершает подписку, и когда я хочу вернуться на подстраницу, тики отсчитываются от нуля.

В конечном счете, есть два разных тика.

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

1. Какую фактическую ошибку вы получаете?

2. Когда вы их используете? Может быть, хранилище еще не загружено.

3. Ha. Я не привык видеть функции, названные с завершением . $ Бросил меня в цикл. Выдает ли поток, возвращаемый с помощью getBuildings$() , более одного раза? Я предполагаю, что нет, это просто запрос к вашим данным?

4. @MrkSef — в этом простом примере это обычный запрос, но в моем приложении это не всегда так. В других, более продвинутых модулях данные изменяются во время работы приложения

5. Я думаю, было бы очень полезно создать StackBlitz, где вы иллюстрируете свою проблему и ожидаемые результаты.