Reduce if/else using RxJS

Parham
Code道
Published in
2 min readSep 12, 2020

Elevate your code series 😊

Photo by Ruiyang Zhang from Pexels

I am trying to decide where the user should land when they open the app.

The logic in plain English would be something like this:

  • If this is the very first time user visits the app show Terms & conditions so they can agree to T&C. This will be saved and the app will remember this choice. It’s a one-off thing.
  • Then If the user has agreed to T&C and has not viewed the app intro, show the introduction. This gives the user a tour of the app features and only happen once as well. So the app keeps a flag remembering this as well.
  • If the user has agreed to T&C and has viewed the intro, just take them to the home page.

The code is using TypeScript and Angular but no major dependency on these tech stacks and you can replicate in any other tech stacks like React or Vue easily.

Original code

// From this ================>

public enter(): Subscription {
return this.termsConditionsStateSelector.agreed()
.pipe(
switchMap((termsAgreed) => this.helpStateSelector.viewed()
.pipe(
map((helpViewed) => ({helpViewed, termsAgreed})),
),
),
tap(({ termsAgreed, helpViewed }) => {
if (!termsAgreed) {
this.navCtrl.navigateRoot('/terms-conditions');
} else if (termsAgreed && !helpViewed) {
this.navCtrl.navigateRoot('/help');
} else {
this.navCtrl.navigateRoot('/home');
}
}),
).subscribe();
}

Refactored with RxJS

// To this ================> private showTnC(): void {
const showTnC$ = this.termsConditionsStateSelector.agreed()
.pipe(
filter((agree) => !agree),
take(1),
tap(() => this.navCtrl.navigateRoot('/terms-conditions')),
);
showTnC$.subscribe();
}
private showIntro(): void {
const showIntro$ = this.termsConditionsStateSelector.agreed()
.pipe(
filter((agree) => agree),
withLatestFrom(this.helpStateSelector.viewed()),
filter(([, viewed]) => !viewed),
take(1),
tap(() => this.navCtrl.navigateRoot('/help')),
);
showIntro$.subscribe();
}
private showHome(): void {
const showHome$ = this.helpStateSelector.viewed()
.pipe(
filter((viewed) => viewed),
take(1),
tap(() => this.navCtrl.navigateRoot('/home')),
);
showHome$.subscribe();
}
public enter(): void {
this.showTnC();
this.showIntro();
this.showHome();
}

What do you think about the readability of code in these 2 examples?
To me first one is easier from understanding the control flow but the second one is more modular and functional.

I like the second one better because:

  • There is no if/else. ✅
  • Each function is doing a single job so concerns are separated.
  • Code is more modular and therefore easier to test.
  • Functions are named based on my DSL.
  • Code is more functional and there is less side effect.
  • I know how many signals to expect so I can use take operator and do not need to worry about unsubscribing.

--

--

Parham
Code道
Editor for

Web & mobile developer, @Auth0Ambassador. Follow me for content on JavaScript, Angular, React, Ionic & Capacitor, Progressive web apps & UI/UX.