Everybody (and apologies if this includes you) is probably sick and tired of hearing me say this, but I strongly believe this topic is strictly out-of-bounds for what app code should care about. It’s extremely important to me as somebody who has invested a lot of time and effort into working with Ionic (and Angular) that framework engineers be free to improve framework stuff without being shackled by bug-compatibility with apps that make unwarranted assumptions about how undocumented internals work.
I don’t care if something is a page, component, tab, service, or whatever. If its lifecycle is managed by DI, then how that lifecycle plays out is also the sole responsibility of the framework. If the framework decides that it wants to aggressively cache things under certain circumstances, and aggressively evict and reinstantiate things under different circumstances, great. You do you, framework. If it decides that it wants to do these things differently tomorrow, also fine.
So, that pushes the question to “how can we as app authors be robust in the face of this uncertainty?”, and I would say this:
You can assume that paired lifecycle events are paired.
ngOnInit will not be called twice in a row without an intervening
ngOnDestroy. So it’s perfectly appropriate to wire up subscriptions to changing sources of data in
ngOnInit and to tear them down in
ngOnDestroy (I personally use @ngneat/until-destroy to do this automatically, but there are many other strategies). Let the object behave as if it was visible or active always. Maybe it’ll get taken in and out of the DOM. Maybe it’ll be hidden. Let the browser and the framework deal with that.
The cardinal sin is conflating the flow of data with the flow of managed app objects. Those are two completely unrelated things and should be managed thusly. ReactiveX is explicitly designed for intelligently managing data flow. Leverage it for that. DI is designed for intelligently managing app object lifecycle. Don’t burden it with data flow management as well.