如何改善Angular组件,以便使用switchMap而不是链接多个订阅?

时间:2019-07-26 08:39:15

标签: angular rxjs

我在Angular应用程序中使用RxJS和Observables处理API调用的结果和处理数据。我已经编写了该组件,它可以正常工作。但是,在进一步研究RxJS和Observables之后,我意识到我使用订阅的方式被认为是不好的做法。

基本上,我有一个订阅可观察对象的函数,然后在订阅内部调用了第二个函数,该函数不使用第一个订阅中的数据,而是订阅一个单独的可观察对象以跟踪特定对象的状态变量。然后在同一个函数中调用第三个方法,该方法使用从第一个订阅传递的数据,并使用它进行API调用并返回一些数据。

我要做的是重构此代码,以便发生相同的行为,但是我正在使用switchMap或其他RxJS函数,从而消除了代码中的不良做法。但是我不确定应该如何使用switchMap等。

我将在下面用我已经描述和注释的每个函数发布代码。

initSettings(){
    this.getOrganisations$().subscribe( (res: AdminOrganisation[]) => {  //This is the first subscription that makes a get request to return an array of AdminOrganisation objects
      this.organisations = res;                                          //this results of this subscription are used to display different input options to the user in the form of
      this.serial = this.organisations[0].serialRef;                     //a mat-list.
      this.currentOrganisationName = this.organisations[0].serialName;
      this.buildSettingsForm(this.serial);
    });
  }

  buildSettingsForm(serial: string) {
    this.ipRangeFormGroup = this.formBuilder.group(
        {
          ipRanges: this.formBuilder.array([])
        }
    );

    this.numArrayElements = this.ipRangeFormArray.length;

    this.ipRangeFormArray.valueChanges.subscribe(changes => {           //This is the second subscription, this one does not require any external inputs but does rely on the 
      this.numArrayElements = this.ipRangeFormArray.length;             //this.ipRangeFormArray being instantiated before it can be called, therefore it has to be create 
    });                                                                 //syncronously and after the first subscription has recieved and utilised data.

    this.setSettings(serial);
  }

  setSettings(serial: string) {                                                     //This is the third subscription, this subscription utilises the this.serial variable that
    this.getSettingsFromSerial$(serial).subscribe(val => {                          //is retrieved by the first subscription and therefore relies on the data from the first
      this.savedSettingsState = val;                                                //observable to function. Like the second sub, this one also needs to occur after the first
      this.ipRestrictionEnabled = val.ipRestrictionSettings.ipRestrictionEnabled;   //has processed its data.
      for (const i of val.ipRestrictionSettings.ipRanges) {
        this.addRange(i.startRange, i.endRange, i.label);
      }
      this.displayForm = true;
    });
  }

一旦我掌握了应该如何使用switchMap / mergeMap / etc,我就会更有信心自己进行重构和改进。但是由于我不是Angular的新手,所以我不确定在使用这些功能来阻止订阅链时的最佳做法是什么,例如我下面的内容。

2 个答案:

答案 0 :(得分:0)

更改量最小,如下所示:

initSettings() {
  this.getOrganisations$().pipe(
    switchMap((res: AdminOrganisation[]) => {
      this.organisations = res;
      this.serial = this.organisations[0].serialRef;
      this.currentOrganisationName = this.organisations[0].serialName;
      return this.buildSettingsForm(this.serial);
    })
  ).subscribe();
}

buildSettingsForm(serial: string) {
  this.ipRangeFormGroup = this.formBuilder.group(
    {
      ipRanges: this.formBuilder.array([])
    }
  );

  this.numArrayElements = this.ipRangeFormArray.length;

  return merge(
    this.ipRangeFormArray.valueChanges.pipe(
      tap(_ => {
        this.numArrayElements = this.ipRangeFormArray.length;
      })
    ),
    this.setSettings(serial)
  );
}

setSettings(serial: string) {
  return this.getSettingsFromSerial$(serial).pipe(
    tap(val => {
      this.savedSettingsState = val;
      this.ipRestrictionEnabled = val.ipRestrictionSettings.ipRestrictionEnabled;
      for (const i of val.ipRestrictionSettings.ipRanges) {
        this.addRange(i.startRange, i.endRange, i.label);
      }
      this.displayForm = true;
    })
  );
}

答案 1 :(得分:0)

仅调用this.getOrganisations $,创建一个switchMap。在switchMap中使用响应并在最后添加return this.getSettingsFromSerial $。因此,在订阅中,您具有最后一个可观察到的响应,例如:-我未检查括号-

initSettings(){
    this.getOrganisations$().pipe(switchMap((res: AdminOrganisation[]) => {  
      //make something with res
      this.organisations = res;                                          
      this.serial = this.organisations[0].serialRef;                     
      this.currentOrganisationName = this.organisations[0].serialName;
      this.buildSettingsForm(this.serial);
      //but return the last observable
      return this.getSettingsFromSerial$(this.serial)
    }))).subscribe(val => {                          
      this.savedSettingsState = val; 
      this.ipRestrictionEnabled = val.ipRestrictionSettings.ipRestrictionEnabled;   
      for (const i of val.ipRestrictionSettings.ipRanges) {
        this.addRange(i.startRange, i.endRange, i.label);
      }
      this.displayForm = true;
    });
  }
  }

  //buildSettingsFrom dont need any thing but serial, and don't call to 
  //setSettings, that you remove

  buildSettingsForm(serial: string) {
    this.ipRangeFormGroup = this.formBuilder.group(
        {
          ipRanges: this.formBuilder.array([])
        }
    );

    this.numArrayElements = this.ipRangeFormArray.length;

    this.ipRangeFormArray.valueChanges.subscribe(changes => {           
      this.numArrayElements = this.ipRangeFormArray.length;             
    });                                                                 
  }