【问题标题】:RxJS http request made multiple times多次发出 RxJS http 请求
【发布时间】:2020-09-11 18:57:48
【问题描述】:

我已将open() 方法附加到我的ng-select 元素,以便使用来自外部API 的数据填充它。

我遇到的问题:如果我打开下拉列表 5 次然后我输入一个字母,它将向服务器发出 5 个 http 请求以填充数据。当我使用虚拟滚动功能时,同样的问题。

component.html

<ng-select [items]="filterValuesBuffer"
         [typeahead]="filterValuesInput$[filter.name]"
         [virtualScroll]="true"
         [multiple]="true"
         [closeOnSelect]="false"
         [loading]="filterValuesLoading[filter.name]"
         [(ngModel)]="filter.filter_values"
         (scrollToEnd)="onScrollToEnd(filter.name)"
         (open)="onFilterOpen(filter.name)"
         typeToSearchText="No values found"
         bindLabel="name">
</ng-select>

component.ts

filterValuesInput$: Map<string, Subject<string>[]> = new Map();

onFilterOpen(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, '')
      .subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = res.filter_values;
      });
}


getFilterValues(filterName, afterKey) {
    return this.filterValuesInput$[filterName].pipe(
      tap(() => this.filterValuesLoading[filterName] = true),
      startWith(''),
      distinctUntilChanged(),
      switchMap(term  => this.search.getFilterValues(filterName, '' + term, '' + afterKey)),
    )
}

如何防止这种行为?

编辑虚拟卷轴:

(scrollToEnd)="fetchMore(filter.name)"

fetchMore(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, this.afterKey)
      .subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = this.filterValuesBuffer.concat(res.filter_values);
      })
  }

【问题讨论】:

  • 你用过share()方法吗?
  • 我没有注意到使用share()有任何区别
  • 试过我的解决方案了吗?

标签: angular rxjs behaviorsubject rxjs-observables


【解决方案1】:

尝试改变你的方法,如下所示:-

public openedFiterName = {};
onFilterOpen(filterName) {
    this.filterValuesLoading[filterName] = true;
    if(this.openedFilterName[filterName]) {
      this.filterValuesLoading[filterName] = false;
      this.filterValuesBuffer = this.openedFilterName[filterName];
      return;
    }
    this.getFilterValues(filterName, '')
      .subscribe(res => {
        this.openedFiterName[filterName] = res.filter_values; 
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = res.filter_values;
      });
}

fetchMore(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, this.afterKey)
      .pipe(take(1)).subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = this.filterValuesBuffer.concat(res.filter_values);
      })
  }

【讨论】:

  • 之前尝试过,但我希望下拉列表中填充数据,即使用户没有搜索任何内容。
  • 感谢您的回答。不幸的是,我使用了多个下拉菜单 ([filterName]),并且通过这种方法,它只会为第一个打开的下拉菜单加载数据(发出 http 请求)。
  • 上面更新了,现在检查一下?
  • 是的,它工作正常!你知道这种方法是否可以用来防止使用虚拟滚动时的多次调用吗?不幸的是,我无法在那里工作
  • 在虚拟滚动上,您需要调用来加载更多数据,对吧?为什么要阻止它?
【解决方案2】:

那是因为您从不退订 getFilterValues()。您应该绑定到(close) 并在那里取消订阅:

onFilterOpen(filterName) {
  this.subscription = this.getFilterValues(filterName, '')
    .subscribe(res => ...);
}

onFilterClose() {
  this.subscription.unsubscribe();
}

您最终可以使用takeWhile() 运算符。见Angular/RxJs When should I unsubscribe from `Subscription`

【讨论】:

  • 感谢您的评论。你知道我怎样才能取消订阅虚拟卷轴吗?请检查我更新的问题
  • (close) 完全相同。可能也在(close) 事件中。
  • 不幸的是,当我多次滚动然后我输入一个字母时,问题正在重现。
猜你喜欢
  • 2022-11-24
  • 2020-05-12
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多