首页 > 解决方案 > 每次加载组件时,订阅数据都会增加 1

问题描述

我在服务中有以下方法来注册数据BehaviourSubject

regFieldsModules(fieldsModules?, field?: Field) {

  // Using the previously stored data from the memory
  if (fieldsModules) {
    this.fieldMod = fieldsModules;
  }

  // Stop processing if fieldModules is null/ undefined
  if (!this.fieldMod) {
    return;
  }

  const groupFields = groupBy(this.fieldMod, 'id');
  const uniqueFields: Field[] = removeDuplicates(this.fieldMod, 'id');

  // Find the default field and assign it to the field
  if (uniqueFields && !field) {
    for (const f of uniqueFields) {
      if (f.isDefault) {
        field = f;
      }
    }

    this.fields.next(uniqueFields);
  }

  this.field.next(field);
  this.fieldModules.next(groupFields[field.id]);
}

并在组件中使用它:

ngOnInit() {
  this.route.params.subscribe(params => {
    this.dataService.fields.subscribe(fields => {
      if (!fields) {
        return;
      }

      for (const f of fields) {
        if (+params['id'] === f.id) {
          this.field = f;
          this.dataService.regFieldsModules(null, this.field);

          this.dataService.fieldModules.subscribe(data => {
            if (data) {
              console.log(data);
              this.groupedModules = groupBy(data, 'moduleId');
            }
          });
        }
      }
    });
  });
}

第一次控制台一次,如果我改变路线并再次访问路线,它会打印两次,第三次打印第三次......它会继续。随着数据的变化,我无法取消订阅,我需要订阅它。

如果我在销毁时取消订阅所有订阅,这可能会解决,但我有另一个用户案例:

我已经下拉标题。在选择时,参数会更改并且组件会刷新。在这种情况下,OnDestroy不会调用该方法。

有没有更好的方法来编写上面的代码?

标签: angularrxjsangular-observable

解决方案


每次销毁组件时,您都必须取消对外部服务的所有订阅,否则您将在应用程序中创建内存泄漏,您还通过使用嵌套订阅而不是高阶运算符来创建泄漏。这是如何正确地做到这一点:

this.sub = combineLatest(this.route.params, this.dataService.fields) // combine subscriptions that don't rely on eachother
             .pipe(
               switchMap(([params, fields]) => { //switchMap into new observables to auto cancel previous subscriptions on new emissions
                 if (!fields) {
                   return EMPTY; // return empty to not emit in the no fields case
                 }

                 const field = fields.find(f => +params['id'] === f.id); // find instead of looping

                 this.field = field; // this block is problematic. Why are you creating side effects here? 
                 this.dataService.regFieldsModules(null, this.field); 

                 return this.dataService.fieldModules; // why switch into a new observable after calling that method?
               })
             ).subscribe(data => { // now I've got the data
               if (data) {
                  console.log(data);
                  this.groupedModules = groupBy(data, 'moduleId');
                }
             });

然后在 ngOnDestroy 中运行:

this.sub.unsubscribe();

推荐阅读