1

我有一个带有 2 个输入(或 mor)的组件,我想:

  1. 当两个值都设置并存在时,第一次触发方法 X
  2. 如果两个值中的任何一个发生变化,则每次触发方法 X
<some-cmp [itemid]="activeItemId$ | async" [userId]="activeUserId$ | async"></some-cmp>

这两个值都可以随时更改,因此我认为使用rxjs构建流可以让我控制一切。我目前的解决方案似乎有点老套,很难测试。我使用2BehaviourSubjects和.combineLatestdebounceTime

@Input() set itemId (id){this.itemId$.next(id)};
@Input() set userId (id){this.userId$.next(id)};

itemId$ = new BehaviourSubject$(null);
userId$ = new BehaviourSubbject$(null);

ngOnInt(){
    combineLatest([
        this.itemId$.pipe(filter(item=>item!===null)),
        this.userId$.pipe(filter(item=>item!===null))
    ]).pipe(
        debounceTime(10),
        switchMap(...)
    ).subscribe(...)
}

所以我的问题是

  1. 有没有更优雅的方式来实现这种行为?
  2. 有没有办法避免debounceTime,这使测试变得困难?

debounceTime用于两个值同时到达并且我不想combineLatest触发该方法两次的情况。

4

2 回答 2

0

Angular 提供了ngOnChanges可以在这种情况下使用的钩子。只要组件的任何输入发生变化,它就会触发ngOnChanges方法。

以下是如何实现此目的的示例:

export class SomeComponent implements OnChanges {
    @Input() itemId: any;
  
    @Input() userId: any;
  
    ngOnChanges(changes: SimpleChanges) {
      const change = changes.itemId || changes.userId;
  
      if (change && change.currentValue !== change.previousValue) {
        this.doSomething();
      }
    }
  
    private doSomething() {
      // Your logic goes here
    }
  }

你的 HTML 现在看起来很干净,你也可以摆脱async

<some-cmp [itemid]="itemId" [userId]="userId"></some-cmp>
于 2021-05-02T14:09:27.380 回答
0

你是对的combineLatest,它只会在每个源发射一次后第一次发射,然后在任何源发射的任何时候发射。

有没有办法避免去抖动时间。[It] 用于两个值同时到达并且我不希望 combineLatest 触发该方法两次的情况。

debounceTime由于 ; 的初始行为,可能没有必要combineLatest。在所有源都发出之前,它不会第一次发出。但是,如果您通常会在短时间内收到来自两个来源的后续排放,则使用debounceTime可能是适当的优化。

有没有更优雅的方式来实现这种行为?

我认为你的代码很好。但是,可能没有必要使用BehaviorSubject,因为您并没有真正使用默认值。您可以使用普通SubjectReplaySubject(1).

您可以将您的结果分配combineLatest给另一个变量并在内部订阅ngOnInit或使用async模板中的管道:

@Input() set itemId (id){ this.itemId$.next(id) };
@Input() set userId (id){ this.userId$.next(id) };

itemId$ = new Subject<string>();
userId$ = new Subject<string>();

data$ = combineLatest([
    this.itemId$.pipe(filter(i => !!i)),
    this.userId$.pipe(filter(i => !!i))
]).pipe(
    debounceTime(10),
    switchMap(...)
);

ngOnInit() {
  this.data$.subscribe(...);
}

于 2021-05-03T01:54:19.433 回答