Угловое наблюдаемое поведение странно

У меня есть заметное, что когда я использую оператор 'rxjs 'share', он ведет себя странно в шаблоне Angular. Вот как я настраиваю свои две наблюдаемые (в сервисе):

this.family = this.store.select(getFamily).pipe(
  tap(family => {
    if (family == null) {
      this.loadFamily();
    }
  }),
  filter(family => family != null),
  share(),
);
this.familyMembers = this.family.pipe(
  map(family => {
    return family.familyMembers;
  })
);

Затем я добавляю видимый элемент familyMember в свой компонент как свойство

this.familyMembers = this.familyService.familyMembers

Моя разметка выглядит примерно так:

 <tbody *ngIf="(familyMembers | async) != null">
        <pre> {{(familyMembers | async) | json}}</pre>

Теперь странно то, что при заполнении familyMembers (массив из двух) <pre> будет оказывать с null внутри, даже после того, как я проверил на ноль с *ngIf,

У меня также есть список, который ничего не отображает следующим образом:

<ng-template ngFor let-familyMember let-i="index" [ngForOf]="(familyMembers | async)" [ngForTrackBy]="trackByFn">

Я знаю что последнее familyMembers Наблюдаемые выбросы были правильными двумя членами семьи, я проверил это с map а также console.log, Шаблон Angular, кажется, видит это как ноль... но тоже нет?

Все работает, если я удаляю share() из семьи наблюдаемой, но tap() работает дважды, что не желательно.

РЕДАКТИРОВАТЬ:

Использование shareReplay() вместо share() решило мою проблему. share() не будет пересылать значения, когда все подписки отписываются.

1 ответ

Решение

Вы должны использовать оператор shared(), так как вы подписываетесь дважды, поэтому вы получили дубликат.
Вы должны изменить свой HTML-код соответственно:

 <tbody *ngIf="familyMembers | async as familyProps">
        <pre> {{familyProps | json}}</pre> 

В первом *ngIf вы проверяете наличие значений, поэтому нет необходимости снова использовать асинхронный канал в другой строке, так как он не будет вызван, если не прошел первый.
Кроме того, когда вы вызываете "как familyProps" и используете его в следующей строке, вы уверены, что этот локальный объект будет доступен при выполнении этой строки. Это может работать без "как", но из вашего комментария я просто добавлю это, чтобы убедиться.

--РЕДАКТИРОВАТЬ
Каждый асинхронный канал, который вы вызываете, тоже будет подписываться, теперь получается, что первая строка с *ngIf ожидает значения, а вторая находится внутри этой оболочки, поэтому она не будет вызываться до тех пор, пока не выполнится первая строка.
Теперь, когда первая строка пройдена, вторая строка попытается подписаться с помощью асинхронного канала, но она уже завершена из-за подписки на первую строку и оператора shared().
Вы можете попробовать это, и это должно работать так же:

<tbody *ngIf="familyMembers | async">
  <pre> {{familyMembers | json}} </pre> 
Другие вопросы по тегам