I do not like to subscribe to observables inside services, as it feels expensive due to the fact that we are not able to unsubscribe from them when we do not need them any more and we all hate memory leaks, right?
So the best way to use this solution will be the way that we would be able to unsubscribe from them when we done listening to that observable.
First, we should not create that service as Singleton service, instead we should make sure the service will be specifically responsible only to handle some functionalities which is related to small part of our app at presentation layer or better to say, it will only take care of logics which related to the Dump component. It does not mean it should not be there for make container/smart components more simple, but in this example I was trying to do it for my Dump component.
Alright, let's say our service is looks like this
import {Injectable, OnDestroy} from '@angular/core';
import {Actions, ofType} from '@ngrx/effects';
import {BehaviorSubject, Observable, Subject} from 'rxjs';
import {takeUntil} from 'rxjs/operators';
import {updateNoteError, updateNoteSuccess} from '../../store/notebook.actions';
import {INote} from '../../interfaces/note.interface';
@Injectable()
export class CreationFacade implements OnDestroy {
private destroyed$ = new Subject();
private updateNote$ = new Subject<void>();
constructor(private actions$: Actions) {
this.listenToUpdateProcess();
}
ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}
updateStatus(): Observable<void> {
return this.updateNote$.asObservable();
}
private listenToUpdateProcess(): void {
this.actions$.pipe(
ofType(updateNoteSuccess),
takeUntil(this.destroyed$))
.subscribe(() => {
this.updateNote$.next()
});
this.actions$.pipe(
ofType(updateNoteError),
takeUntil(this.destroyed$))
.subscribe((error) => {
this.updateNote$.error(error)
});
}
}
Have you noticed this line?
@Injectable()
export class CreationFacade implements OnDestroy
Yes, I've implemented OnDestroy interface to my service and Angular will call this lifecycle only if we provide it to the corresponding component and only there but not in the Module.
So meta data we will pass to to @Component
decorator will be like this
@Component({
selector: 'app-note-writing',
templateUrl: './note-writing.component.html',
styleUrls: ['./note-writing.component.scss'],
providers: [CreationFacade]
})
Isn't that great?
Now we can relax and be sure those observables inside the service will be unsubscribe in the end of the process and we will have happy users after all!
Thank you for reading,
Hope you enjoyed.
Top comments (3)
great article. im curious if we can build a codemod that can at least "detect" the anti-pattern for devs and leave a comment for them to fix it? do you think it would be interesting?
if yes, what would be the detection logic?
something along the line of: hasDirectSubscription && (lacksOnDestroy || lacksUnsubscriptionLogic)?
can you help me share a link like this with some examples? go.codemod.com/Lf3JzbW
First of all Kudos to this brilliant post. Can you please suggest me with following scenario.
I have such similar kind of scenario, I want to connect to IoT devices using MQTT, in Angular. I was looking for such kind of solution where I can create a service or Facade (as above) , so I can access it from all page. I have different type of topics to subscribe.
I was thinking to use this service directly in app.component.ts file, but i have performance related concern,
What I have done till now is, E.g I have a temperature page. if i do active on temperature page then it works fine, subscribe to topic. What I want is to subscribe to temperature topic event thought I am not active on temperature page.??
hope I'm able to explain.
I can see a Redux pattern may be helpful here!
It feels like having NgRx stores responsible for storing that information!