Component lifecycles differs on nativescript-angular and angular2 on web.
See original GitHub issueI ran into this problem and I’ll try to explain it here.
With nativescript-angular
the lifecycle hook ngOnDestroy
isn’t called when we navigate away from a page as it would be on web. Navigating back reuses the old component with nativescript-angular
but a new instance is created on web.
I’ve based an example on Nathan Walker’s angular2-seed-advanced
:
https://github.com/m-abs/angular2-seed-advanced/tree/ngondestroy-not-triggered
I’ve two component for my routes: HomeComponent AboutComponent
Each component have a instanceNo
, so we can identify multiple instances of the component.
Action | Web | TNS |
---|---|---|
Launch application | HomeComponent<1>.ngOnInit() is called | HomeComponent<1>.ngOnInit() is called |
Click on ‘ABOUT’ | HomeComponent<1>.ngOnDestroy() followed by AboutComponent<1>.ngOnInit() | AboutComponent<1>.ngOnInit() |
Click on ‘HOME’ | AboutComponent<1>.ngOnDestroy() followed by HomeComponent<2>.ngOnInit() | HomeComponent<2>.ngOnInit() |
Click back | HomeComponent<2>.ngOnDestroy() followed by AboutComponent<2>.ngOnInit() | HomeComponent<2>.ngOnDestroy() |
Click back again | AboutComponent<2>.ngOnDestroy() followed by HomeComponent<3>.ngOnInit() | AboutComponent<1>.ngOnDestroy() |
As you can see the two behaves very differently.
On web:
- Navigate to a new page, the current component is destroyed and a new is created.
- Navigating hitting back, the current component is destroyed and a new is created.
With nativescript-angular:
- Navigate to a new page, creates the new component but leaves the current component as is.
- Navigating hitting back, the current component is destroyed and the old component is reused.
If you want to try for yourself, checkout my branch ngondestroy-not-triggered
and run:
For web:
npm run start
For nativescript-angular with android:
npm run start.livesync.android
Shouldn’t the two behave the same? So components are destroyed when we navigate from a page and (re)created when we navigate to the page?
Issue Analytics
- State:
- Created 7 years ago
- Reactions:10
- Comments:30 (11 by maintainers)
Let’s do a little summary so far
Subscriptions And CleanUp
When using page-navigation
ngOnInit()
will be called the first time the component is navigatedTo andngOnDestroy()
will be called when navigating back from the page with the component (when it is removed form the navigation stack). When navigating forward(deeper in the app) those hooks will not be called. The component instance will be preserved as it is still connected to a page that lives inside the native navigation stack.However, you might want prevent it from updating while not shown. So far I think @m-abs solution of using page events would be the simplest. You might call the
ngOnInit()/ngOnDestroy()
hooks directly, but it’s good idea to guard them with a flag to prevent double execution.Using ActivatedRoute and Params
Normally, in Angular you would inject
ActivatedRoute
and read parameters from it. Your component will be reused if you do a subsequent navigations to the same route while only changing the params. That’s whyparams
anddata
insideActivatedRoute
are observables.In NativeScript when navigating back to an existing page your component will not be re-created. Angular router will still create an new instance
ActivatedRoute
and put all params in it, but you cannot get hold of it trough injection as no constructor is called.The Solution: In NativeScript you can inject
PageRoute
which has anactivatedRoute: Observable<ActivatedRoute>
inside it. Each time a newActivatedRoute
instance is created for this re-used component it will be pushed in this observable, so you can still get you params:So, instead of:
You do:
Why So Complicated
Native platforms preserve the views in the native navigation stack when navigating deeper. So we need to preserve the components that are connected to those views too. This is done in the
<page-router-outlet>
. However, there are some limitations in terms of how Nativescript plugs into the router live-cycle explained in angular/angular#7757. I hope in future version of angular these will be resolved so we can narrow the gap between using<page-router-outlet>
and the stock<router-outlet>
@vakrilov Thank you for the suggest, I’ll try it when I get back to work 😃
I’ll can try to elaborate, sorry for the long text 😃
Our project is based on
angular2-seed-advanced
, so we share code between the {N} -version and the web-version of our project. The project is an audiobook-player that shows HTML-content synced to the audio during playback. We render the HTML-content with ourcontent-viewer
-component. On web we use the component as is and in {N} it runs in a small ng2-webapp inside aweb-view
. Our page-component sets up events and subscriptions to make this work in ourngOnInit()
hook and they’re removed in ourngOnDestroy()
hook.Since the page-component lives on after navigation from it, the subscriptions and events created in
ngOnInit()
will still be active, this means that theweb-view
/content-viewer
-component still does work that is now unneeded. We also risk having two instances of theweb-view
/content-viewer
-component running at the same time. If the user navigates to the page again without going back, since that won’t reuse the component.I also think the behavior goes against what the ng2-docs imply.
From: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#hooks-overview
From: https://angular.io/docs/ts/latest/guide/router.html#!#route-parameters
We can of cause use the
Router.events
observable as a workaround, but I’d much rather just rely on the hook ng2 components have for it. I’d also prefer the same behavior (where possible) on both web and in {N}, otherwise it can be surprising for the developers.I can see it’s done intentionally here: https://github.com/NativeScript/nativescript-angular/blob/master/nativescript-angular/router/page-router-outlet.ts#L112 And I do understand the benefits of caching components like that, but what about larger app with many pages where the user don’t necessarily navigates back? Don’t we risk it accumulates old components and thus causing the leaks the ng2-docs mention?