Ionic 4 and the Lifecycle Hooks in Angular

There are a lot of questions related to Ionic 4 and the Lifecycle Hooks. There are new issues at the Ionic Github Repository where people complain that the Lifecycle Hooks are not working. So I will tell you in this article when the Lifecycle Hooks are running in Ionic 4.

Keep in mind: This post covers the package @ionic/angular— and so the combination of Ionic 4 and Angular. Ionic 4 will be available for other frameworks (like Vue), too (or use it standalone without any other framework).

For example:

When I navigate from the home to another route, the lifecycle ngOnDestroy of the home component is not executed

But why? Let’s start how Lifecycle Hooks working in Ionic 4!

TL;DR

Please skip to the end of the page, I added a short summary ;)

Ionic 4 uses the Angular Lifecycle Hooks

The first good news: Ionic 4 uses the Angular Lifecycle Hooks! So you can use ngOnInit, ngOnDestroy and all other Lifecycle hooks and do not have to remember the special ones from Ionic. Read more about Angular Lifecycle Hooks at the official documentation!

Short recap: How it was in Ionic 3

If you already used Ionic 3, then you will used ionViewDidLoad, ionViewWillEnterand ionViewDidEnteron pushing a new view and if the current view pops away you use ionViewWillLeave, ionViewDidLeaveand ionViewWillUnload. Also two nav guards ( ionViewCanEnter and ionViewCanLeave) . At the Ionic Blog you find a very good post about it and the following image which shows the lifecycles very good:

Ionic 3 lifecycle — Source: blog.ionicframework.com

Are these lifecycles still working?

Yes, Ionic has still this lifecycles (see in Github). Only ionViewDidLoad has been replaced with Angular Lifecycle (use ngOnInit now).

Also the two nav guards ( ionViewCanEnter and ionViewCanLeave) were removed because Angular Router provides route guards, so you can determine if a user can access a route and can leave a route ( canActivate and canDeactivate ). ionViewWillUnloadis not required if you use Angular, here you have to use ngOnDestroy . But Ionic 4 is framework independent, so in other cases this can be useful. ionViewWillEnter, ionViewDidEnter ionViewWillLeaveand ionViewDidLeave are still very nice, but more about it later!

Ionic 4 and ion-router-outlet

If you already created a sample app like the blank starter, tabs starter, or sidemenu starter, you will notice the <ion-router-outlet></ion-router-outlet> instead of <router-outlet></router-outlet> in your app.component.html and a

{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }

in your app.module.ts.

You can still use <router-outlet></router-outlet> with the Ionic 4 components, but the Ionic team added a special feature to it:

A “stack” functionality like in Ionic 3

Okay! And what does this mean?

Normally if you switch from one route to another in Angular, the components will be destroyed immediately. The Ionic router keeps the components (Ionic calls it pages — I like this terminology) in a stack. They are not destroyed by default.

Show me in practice

Enough theory, let’s see how it works in practice. I created a new project based on the starter package of Ionic and created two new pages: ListPage and ListItemPage. ListPage contains a list of items and if I tap on a item, I will redirect to the ListItemPage.

Lifecycle in Ionic 4

The GIF above shows a lot of details, so I will guide you through it:

  1. We start on ListPage and I tap on a item, so I will navigate to the ListItemPage (I navigate forward). Take a look at the console: No ngOnDestroy! But this is not a bug!

Here is the source code. I am using NavController from Ionic (navigateForward() is the same like router.navigate() )

gotoItem() {
// navController is instanceof NavController from '@ionic/angular'
// the following is the same like this.router.navigate()
this.navController.navigateForward(['/list-item']);
}

2. I am on ListItemPage now! I am using the <ion-back-button>, but you can also use navController.navigateBack(url). If I tap on the back button, you see ‘ngOnDestroy ListItem’ in the console.

3. If I take a look at the inspector and see the elements, you see the stack functionality. The ListPage is still in our DOM, it’s not visible because it’s behind the ListItemPage. If I navigate backward, the ListItemPage will be destroyed (removed from the stack — also removed from DOM).

In short: Whenever you wonder, why ngOnDestroy is not firing, just take a look at the DOM inspector and you will see that the component is still there. It’s not destroyed yet, so ngOnDestroy is not firing!

Earlier I talked about the special Ionic Lifecycles. We can use them here now! If you leave ListPage and want to cancel the observables, just do it inside ionViewWillLeave or ionViewDidLeave. If the component becomes active again, just subscribe to that observable inside ionViewWillEnteror ionViewDidEnter. Everything in ngOnInit will not be triggered because the component was already initialized.

And when I want to destroy ListPage ?

If you do not want to push ListPage into the stack, just use navigateRoot() of the NavController!

gotoItem() {
this.navController.navigateRoot(['/list-item']);
}

If you execute this now, ngOnDestroy will be triggered, the component will be removed from DOM. It’s not added to the stack.

And what about ion-tabs?

UPDATE 2018–12–11: The Ionic dev team refactored tabs and so tabs will provide lazy loading! This is working since beta.18.

Summary: Lifecycles in Ionic 4

Okay Paul, nice background information, but what should I memorize?

  1. Ionic 4 extends the Router Navigation of Angular
  2. Ionic 4 introduces a stack functionality (like in Ionic 3)
  3. Ionic 4 adds new Lifecycle Hooks to Angular: 
    ionViewWillEnter — Fired when entering a page (also if it’s come back from stack)
    ionViewDidEnter — Fired after entering (also if it’s come back from stack)
    ionViewWillLeave — Fired if the page will leaved (also if it’s keep in stack)
    ionViewDidLeave — Fired after the page was leaved (also if it’s keep in stack)
    ionViewWillUnload — In Angular not firing because here you have to use ngOnDestroy
  4. Except ionViewDidLoad (because it’s the same like ngOnInit) and the two nav guards all Lifecycle hooks from Ionic 3 are still available
  5. ngOnInit will not be triggered, if you come back to a page after putting it into a stack
  6. By default, if you navigate forward, the current page keeps in stack, so NO ngOnDestroy will be triggered. Only if you set the new page as root (navController.navigateRoot())) or you navigate backwards, it will be removed from stack
  7. If you want to cancel Observables, just do it ionViewWillLeave or ionViewDidLeave and subscribe to it again in ionViewWillEnter or ionViewDidEnter
  8. Take a look at the DOM inspector, there you can see that your page is still in the stack
  9. If you use the Angular Router, pages will add to the stack. I recommend to use the Ionic Angular NavController because here you can use the new stack functionality
  10. With the upcoming beta.18, also ion-tabs will be lazy load!

Do you have more questions or I write something not correctly, just let me know and post a comment!