To expand on @AaronSterling’s comment, I never explicitly type unsubscribe any more, after reading this article. Instead, I use the following idiom:
private _tripwire: Subject<boolean>;
ionViewWillEnter(): void {
this._tripwire = new Subject<boolean>();
observableFoo()
.pipe(takeUntil(this._tripwire))
.subscribe(foo => this.foo = foo);
observableBar()
.pipe(takeUntil(this._tripwire))
.subscribe(bar => this.bar = bar);
// repeat ad infinitum
}
ionViewWillLeave(): void {
// it would be nice to be able to just complete, but that won't trigger takeUntil
this._tripwire.next(true);
// strictly speaking probably not necessary, but i do it in case the previous line gets to go away at some point
this._tripwire.complete();
this._tripwire = undefined;
}
Instead of willEnter/willLeave, these can be paired up in didLoad/willUnload or any other set of matching lifecycle events as befits your situation.
I use a very similar approach, but don’t include
this._destroy$ = undefined;
Where _destroy$ = _tripwire.
What’s your reasoning for that additional line? Should I be using it?
Edit: I’m using that approach, along with switchMap, combineLatest, etc. in pure Angular projects, not Ionic. I know there’s a difference in how components are “destroyed”
Definitely a most practical solution. I use the observable pipe, takeUntil, switchMap, etc. then subscribe because a majority of my data needs to be sorted in some fashion.
But the async pipe is a gift from the computer gods when applicable.
I sure would like to see the ability to sort an observable stream one of these days.
So to summarise: streams that do not complete during the lifetime of component need unsubscription, which ideally should be done by forcing the completion using the patterns shown above (or use async pipe). .
So to summarise more complete: streams that do not complete during the lifetime of component need unsubscription, which ideally should be done by forcing the completion using the patterns shown above (or use async pipe). And if you reference to your subscription using a variable, assign it to undefined after completion.
He wasn’t undefining the subscription, but the tripwire Subject. To my eye, that’s unnecessary (esp in this toy example) but good style, because if the Subject emits unexpectedly, it could have consequences for everything still listening to it. If you undefine it as part of your teardown logic,you guarantee yourself that a source of hard-to-debug errors will not exist.
All that said, I’d already seen the article @rapropos linked, and I wasn’t convinced by it. I think there’s a benefit to forcing yourself to know exactly what you’re tearing down in your teardown logic. But it’s a very clever idea. Maybe if you have 50 Observables on your page, and you need to edit some in and out in each update? But I only have a few Observables per “code piece.”: (Though I have a couple dozen providers in one project, so I just segmented things that way.)
@AaronSterling, It seems strange that a Subject could emit after completion. Chalk it up to the imperfections of computer tech??
I certainly don’t have 50 observables on any page, but I do tend to have 2 - 3 observables on init that get items like a user id, an app state boolean or string, etc.
Those I always use take(1) on so don’t need to think twice about them. But with the addition of a couple more Observables, I guess I just prefer reducing my code by a few lines when possible. Or I just like feeling clever.
Though avoiding importing { Subscription }, Typing each subscription, then assigning and unsubscribing does seem to reduce my lines to a decent degree.
I like having teardown logic live right next to buildup logic. It’s sort of a cousin to why I prefer using initializers over splitting up declarations and doing initialization in constructors (where possible). Then if I add a new Observable later, I only have to edit one place, because it can share the same tripwire. Golang has this concept burned into the language itself with its defer statement, and I find it very helpful in dealing with things like rolling back SQL transactions in error situations.
If you screwed up your code and the Subject did something you didn’t intend for it to do. Finding that error can be a pain and a half, because your mistake might be removed from the effect you are seeing.
Not sure if it’s applicable to the go-between with you and @rapropos
I’m fetching a switchMap / query action from detailService, and implementing it in my constructor.
My provider of course contains some logic, i. e