【问题标题】:How do I concatenate values returned from an async pipe in Angular如何连接从 Angular 中的异步管道返回的值
【发布时间】:2020-10-14 01:05:10
【问题描述】:

我无法理解该怎么做。

最初我有一个方法(获取评论),使用下面的订阅方法,当评论返回到组件时,它们被连接到任何现有评论,我用异步管道重新实现了它,所以现在我'我只是将评论设置为reviews$,而不是像以前那样连接它们,这不是我想要的。

// initial method
reviews: IReview[] = [];
getReviews() {
  this.membersService.getReviews(this.member.id, this.skip)
    .subscribe(response => {
      this.reviews = [...this.reviews, ...response];
      this.skip = this.skip + 10;
    });
}

这是我修改后的获取评论的方法,但不知道如何像以前那样连接结果。我该怎么做?

仅供参考 - 我还注意到这个 getReviews() 现在被多次触发。我不确定这是来自管道还是水龙头方法。

reviews$: Observable <IReview[]> ;
getReviews() {
    this.reviews$ = this.membersService.getReviews(this.member.id, this.skip)
    .pipe(
      tap(response => {
        this.skip = this.skip + 10;
      })
    );

【问题讨论】:

  • 我认为异步管道更适用于可观察对象,但不适用于订阅
  • 我添加了一个未测试的答案,但我认为tap 没有返回值,这可能是您订阅后没有获得值的原因
  • 您想为此使用扫描运算符来累积一段时间内的响应。
  • 您能否在答案中提供一个示例,适用于我的场景?\
  • concatmap 呢?那行得通吗?

标签: html angular typescript asynchronous observable


【解决方案1】:

我会像下面这样处理问题,

  • 定义一个主题来存储评论。我正在使用BehaviourSubject 将评论的初始值设置为空数组[]
reviewsSubject$ = BehaviourSubject<IReview[]>([]);
reviews$ = this.reviewsSubject$.asObservable();
  • 接下来定义获取评论的触发器。 getReviews() 函数将简单地通过在 Subject 上调用 next() 函数来触发 observable
  triggerSubject$ = new BehaviorSubject(null);
  trigger$ = this.triggerSubject$.asObservable();
  getReviews = () => this.triggerSubject$.next(null);

  • 接下来将结合触发器和可观察对象来获取评论。我将使用来自rxjscombineLatest
  newReviews$ = this.membersService.getReviews(this.member.id, this.skip);
  combinedReviews$ = combineLatest([this.newReviews$, this.trigger$]).pipe(
    tap(() => (this.skip = this.skip + 10)),
    tap(([newReviews]) =>
      this.reviewsSubject$.next([...this.reviewsSubject$.value, ...newReviews])
    )
  );

  • 最后我们订阅combinedReviews$我会用async管道

在 HTML 中

<button (click)='getReviews()'>Get More Reviews</button>
<ul *ngIf="combinedReviews$ | async">
    <li *ngFor="let review of reviews$ | async">{{ review.name }}</li>
</ul>

总体而言,代码将是

export class AppComponent {
  constructor(private membersService: MembersService) {}
  skip = 0;
  member = { id: 1 };
  reviewsSubject$ = new BehaviorSubject<IReview[]>([]);
  reviews$ = this.reviewsSubject$.asObservable();
  triggerSubject$ = new BehaviorSubject(null);
  trigger$ = this.triggerSubject$.asObservable();
  getReviews = () => this.triggerSubject$.next(null);
  newReviews$ = this.membersService.getReviews(this.member.id, this.skip);
  combinedReviews$ = combineLatest([this.newReviews$, this.trigger$]).pipe(
    tap(() => (this.skip = this.skip + 10)),
    tap(([newReviews]) =>
      this.reviewsSubject$.next([...this.reviewsSubject$.value, ...newReviews])
    )
  );
}

【讨论】:

  • 嗨欧文。感谢您花时间回答我的问题。看看你提供的这段代码,它似乎与我最初所拥有的有点相关,我尝试使用异步管道重构我的初始代码的目的是避免调用取消订阅。 (我从可观察的在线指南中看到的建议)。我的问题是,使用我的初始代码与使用您的代码取消订阅会不会更容易?只是一个试图更好地理解 observables 的人提出的问题
  • 我的代码使用 observables,但使用异步管道订阅 observables。由于它使用异步管道,因此您无需调用 unsubscribe
  • 嗨欧文,我知道它不使用退订,但看起来它似乎比退订要复杂得多(更多代码,更多参与)。那么,使用您的示例与在 ngondestroy 中取消订阅相比有什么好处吗?
  • 您的解决方案似乎有点过度设计。 ??
  • 这取决于,假设您有 100 个组件,并且您正在订阅和取消订阅,您将有 200 个导入,用于 OnInit 和 OnDestroy,100 个订阅和 99 个取消订阅,哎呀!您忘记取消订阅其中之一,并且您遇到内存泄漏,调试变得非常困难。使用异步管道还可以轻松实现 OnPush changeDetection,您可以看看它,这完全与代码的性能和可维护性有关
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
相关资源
最近更新 更多