组件:
@Component({
templateUrl: 'widget.ng.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
readonly purchases$ = of([]);
readonly refunds$ = new Subject<Refund[]>();
constructor() {
// this.refunds$.subscribe();
}
ngOnChanges() {
this.refunds$.next([]);
模板:
<div #containerDiv>
<collapsible-group>
<div collapsible #collapsibleDiv>
<mat-tab-group>
<mat-tab>
<ng-container *ngIf="purchases$ | async as purchases; else loading">
<purchases-table
[purchases]="purchases">
</purchases-table>
</ng-container>
</mat-tab>
<mat-tab>
<ng-container *ngIf="refunds$ | async as refunds; else loading">
<refunds-table [refunds]="refunds">
</refunds-table>
</ng-container>
</mat-tab>
</mat-tab-group>
<!-- Loading State -->
<ng-template #loading>
Loading...
</ng-template>
</div>
</collapsible-group>
</div>
在此代码中:purchases
按预期加载,而refunds
不按预期加载。但是,如果我取消注释构造函数中的行,则refunds
也会按预期工作。
异步管道似乎未预订主题,或者它可能无法在ngOnChanges之前预订主题。是这样吗?
可能与OnPush有关吗?
答案 0 :(得分:2)
使用行为主题代替,因为您可以为它提供一个空数组作为初始值,并且您不必担心何时调用next。
refunds$ = new BehaviorSubject<Refund[]>([]);
订阅主题只会获得订阅发生后发出的值,BehaviorSubjects会获得订阅时最后发出的值。
答案 1 :(得分:0)
您一直是软件中两个协作缺陷的受害者。
第一个是ngOnChanges()
。您想的时候并没有准确地称呼它。仅当设置了@Input值时才调用它,并且在第一次调用时,调用发生在对ngOnInit()
的调用之前和模板的某些初始化完成之前
另一个是Subject
。由于它是RxJS中其他几个Subject的基类,因此您自然会认为它是您的默认类。不是这样!实际上,很少使用基数Subject
,因为它根本没有缓冲能力。编写Angular代码时,通常要使用BehaviorSubject
(当您有初始值时)或ReplaySubject
(当您没有初始值时)。
我创建了一个Stackblitz app来说明您的选择,其中包含三个虚构的Observable。
您可以继续使用Subject
,其缺点是根本无法工作。
您可以使用ReplaySubject
或BehaviorSubject
并继续从ngOnChanges()
触发它。这可行...可能。 ngOnChanges()
有点奇怪(在我看来),但是它的行为是系统的,您可以让它执行所需的操作。
我个人的喜好是使用ReplaySubject
或BehaviorSubject
并将其触发@Input set()
。我认为这是可读性,效率和灵活性的良好结合。有关更多信息,请参见here。