零件:
@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有关?
使用行为主题,因为您可以将空数组作为初始值,并且您不必担心调用next时。
refunds$ = new BehaviorSubject<Refund[]>([]);
对主题的订阅只会获得订阅发生后发出的值,BehaviorSubjects在订阅时获取最后一个发射值。
您一直是软件中两个合作缺陷的受害者。
首先是ngOnChanges()
。当你想到时,它并没有完全被称为。只有在设置了@Input值时才会调用它,并且在第一次调用时,调用在调用ngOnInit()
之前和模板的某些初始化完成之前进行。
另一个是Subject
。因为它是RxJS中其他几个Subject的基类,所以你自然会认为它是你的默认类。不是这样!事实上,很少使用基础Subject
,因为它根本没有缓冲能力。在编写Angular代码时,通常需要使用BehaviorSubject
(当你有一个初始值时)或ReplaySubject
(当你没有时)。
我用三个组成的Observables创建了一个Stackblitz app来说明你的选择。
你可以继续使用Subject
,它的缺点是根本无法工作。
你可以使用ReplaySubject
或BehaviorSubject
并继续从ngOnChanges()
触发它。这很有用......可能。 ngOnChanges()
有点奇怪(在我看来),但它表现得系统化,你可以让它做你需要的。
我个人的偏好是使用ReplaySubject
或BehaviorSubject
并从@Input set()
触发它。我认为这是可读性,效率和灵活性的良好结合。有关更多信息,请参阅here。