Угловое наблюдаемое поведение странно
У меня есть заметное, что когда я использую оператор '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>