Which is the best way to use BehaviorSubject with Ionic4?

Hi,
I’m using some BehaviorSubject in an Ionic4 app.

I’ve defined them in a service:

@Injectable({
  providedIn: 'root'
})
export class DeviceManager {
	public deviceSpeed: BehaviorSubject<number>;
	...
}

And I’m using them in some pages in this way:

ngOnInit() {
    this.devicesManager.deviceSpeed.subscribe((value) => {
		// do things
      }
}

I have some doubts:

  • Is ngOnInit the right method in which subscribe the BehaviorSubject?
  • Is unsubscribe mandatory?
  • In which method should I unsubscribe the BehaviorSubject?

Thank you very much

cld

I’m going to start by answering two questions you didn’t ask:

Should I use providedIn: "root"?

No, because it makes it impossible to mock out the service for testing.

Should I expose my Subjects as public service properties?

No, because it locks you into a particular implementation and leaks details of that implementation to clients. Make the Subject private and expose it via a method like:

watchDeviceSpeed(): Observable<number> {
  return this.deviceSpeed;
}

You sometimes see people use asObservable(), but I think that’s pointless. Simply returning the Subject as an Observable will cause anybody trying to mess around in its guts to get build errors.

Now for the questions you did ask:

Is ngOnInit the right method in which subscribe the BehaviorSubject?

It’s a perfectly fine choice absent any specific considerations that would dictate otherwise.

Is unsubscribe mandatory?

“Mandatory” is a loaded word, but yes, you really want to unsubscribe, lest you leak subscriptions.

In which method should I unsubscribe the BehaviorSubject?

Whatever pairs with where you subscribed. If you subscribe in ngOnInit, tear down in ngOnDestroy.

One more bonus question you didn’t ask:

Do I have to do all this manually?

No. I use and recommend @ngneat/until-destroy, so all you have to do is this:

@UntilDestroy()
@Component(...)
export class Page {
  constructor(private deviceManager: DeviceManager) {}
  ngOnInit(): void {
    this.deviceManager.watchDeviceSpeed().pipe(untilDestroyed(this))
      .subscribe(speed => {...});
   }
}
1 Like