异步管道似乎在onChanges之前没有收听Subject

时间:2019-04-25 19:19:40

标签: angular typescript rxjs angular-material

组件:

@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有关吗?

2 个答案:

答案 0 :(得分:2)

使用行为主题代替,因为您可以为它提供一个空数组作为初始值,并且您不必担心何时调用next。

refunds$ = new BehaviorSubject<Refund[]>([]);

订阅主题只会获得订阅发生后发出的值,BehaviorSubjects会获得订阅时最后发出的值。

答案 1 :(得分:0)

您一直是软件中两个协作缺陷的受害者。

第一个是ngOnChanges()。您想的时候并没有准确地称呼它。仅当设置了@Input值时才调用它,并且在第一次调用时,调用发生在对ngOnInit()的调用之前和模板的某些初始化完成之前

另一个是Subject。由于它是RxJS中其他几个Subject的基类,因此您自然会认为它是您的默认类。不是这样!实际上,很少使用基数Subject,因为它根本没有缓冲能力。编写Angular代码时,通常要使用BehaviorSubject(当您有初始值时)或ReplaySubject(当您没有初始值时)。

我创建了一个Stackblitz app来说明您的选择,其中包含三个虚构的Observable。

您可以继续使用Subject,其缺点是根本无法工作。

您可以使用ReplaySubjectBehaviorSubject并继续从ngOnChanges()触发它。这可行...可能。 ngOnChanges()有点奇怪(在我看来),但是它的行为是系统的,您可以让它执行所需的操作。

我个人的喜好是使用ReplaySubjectBehaviorSubject并将其触发@Input set()。我认为这是可读性,效率和灵活性的良好结合。有关更多信息,请参见here