Navigation multiplateforme: pourquoi NavController a vaincu angular / router dans Ionic 4



Bonjour à tous! Je m'appelle Nikita Zhigamovsky, programmeur chez KitApp, et je veux parler de mon expérience dans la construction de la navigation dans Ionic 4: le problème que j'ai rencontré et sa solution.

Je développe des solutions multi-plateformes pour les applications mobiles depuis 2018. J'avais l'habitude de travailler sur Ionic 3ème version, mais avec le temps, la fonctionnalité évolue, j'ai décidé de passer à une version plus récente, et les moments et bugs ennuyeux du modèle précédent dans Ionic 4 semblent avoir déjà été corrigés.

Il semblerait que ce qui pourrait mal tourner. Enfin, nous avons la fonctionnalité d'un routage angulaire normal, et non l'ancien NavController avec toutes ses lacunes. Même sur le site officiel d'Ionic, le guide de routage indique que la navigation par programme dans les pages vaut la peine d'utiliser les méthodes angulaire / routeur. Mais il y avait quelque chose qui m'a fait revenir à l'ancien NavController.

L'essence du problème


Un bug intéressant a été remarqué. Supposons que vous ayez un menu latéral, vous l'avez créé en utilisant le volet de partage d'ions. Vous avez également des pages distinctes dans le menu et vous souhaitez passer de celles-ci à d'autres pages qui sont dans le menu. Naviguez à l'aide de Router.navigateByUrl ('/ menu / ...'). Ensuite, nous appelons la page de menu A, et la page séparée du menu - B. Mais il y en a un MAIS!

Supposons, à la page A, qu'une certaine logique soit déclenchée dans l'événement ngOnInit. Vous accédez à la page B à l'aide du routeur et remarquez que la page de menu est toujours active - elle n'a pas été supprimée. Par conséquent, si vous revenez à la page A, l'événement ngOnInit ne fonctionnera pas, car l'événement ngOnDestroy de cette page n'a pas fonctionné. Il semblerait que tout soit logique. À de tels moments, ils ont généralement recours à l'une des méthodes du cycle de vie, non pas l'angulaire, mais l'ionique - ionViewWillEnter. Il se déclenche lorsque vous accédez à la page dès qu'elle devient active. Tout semble aller bien, ça va parfaitement, mais il y a un certain nombre de conventions.

Aucune des options pour une action adéquate sur la page A ne fonctionnera lorsque vous y accédez, si cette transition ne provient pas des pages qui sont dans le menu. Vous ne pourrez pas suivre la transition vers cette page, car, je le répète, elle est toujours ouverte et fonctionne silencieusement sous d'autres pages, par exemple, sous la page B.

Quelques exemples illustratifs:

ionViewWillEnter fonctionnera si vous avez la structure de page suivante:

1) Pages séparées

- page1
- page2
- page3

Dans cet exemple, lorsque je vais sur chaque page, ionViewWillEnter fonctionnera parfaitement. (page1 => page2, page2 => page3, etc.)

2) Menu / onglets

- menu
- menuPage1
- menuPage2
- menuPage3
Dans cet exemple, tout ira aussi bien: la méthode ionViewWillEnter se déclenchera chaque fois que vous vous rendrez sur l'une des pages (menuPage1 => menuPage2, menuPage1 => menuPage3, etc.).

Mais dans l'exemple ci-dessous, tout est plus compliqué:

- menu
- menuPage1
- menuPage2
- menuPage3
- loginPage
- signupPage

C'est là que les problèmes de routage angulaire standard commencent. Lors de la navigation à l'intérieur des pages de menu (menuPage1 => menuPage2 => menuPage3) - la méthode ionViewWillEnter fonctionnera comme d'habitude, de la même manière lors de la navigation entre les pages individuelles (loginPage => signupPage). Mais dès que nous commençons à nous déplacer entre des pages distinctes et des pages de menu (loginPage => menu / menuPage1 ou menu / menuPage3 => signupPage), ni la méthode ngOnInit ni ionViewWillEnter ne fonctionnent. ngOnInit ne fonctionnera pas car la page n'a pas été détruite, ce qui est logique. Mais pourquoi ionViewWillEnter n'a-t-il pas fonctionné?

Sur la base de la documentation, ionViewWillEnter fonctionne à l'intérieur de piles de routage distinctes (le mot-clé «individuel») ou entre des pages individuelles, ou à l'intérieur de menus / onglets. Mais pas dans la structure mixte des pages individuelles et des menus / onglets. Étrange, mais cela est considéré comme un comportement normal. Dans le même temps, ce n'est pas exactement le comportement attendu par les utilisateurs, surtout si l'on considère le nom des hooks du cycle de vie :).

Alors, comment résoudre ce problème?


Ayant visité de nombreux forums, mais n'ayant pas vu de solution normale, et ayant vu des hacks de vie douteux qui ne fonctionnent pas toujours, il devient clair que quelque chose d'autre est nécessaire. Quelque chose qui va changer la fonctionnalité de transition entre les pages de tout type.

Que faire dans ce cas? Bien sûr, jetez le routeur en enfer et oubliez-le, car il y a toujours notre NavController précédemment détesté et maintenant si bon.

La principale différence entre la méthode NavController.navigateRoot () est qu'après être passé à une autre page, la précédente est automatiquement détruite! Et lorsque vous y basculez à nouveau, la méthode ngOnInit et ionViewWillEnter fonctionnent toutes les deux! En fait - c'est la solution parfaite - sans béquilles et fonctions auto-écrites douteuses.

Le plus cool est qu'il fonctionne avec n'importe quelle structure de page: même entre normal, même à l'intérieur du menu, même de type mixte, comme dans le dernier exemple.

Résumez les aspects positifs:

  1. NavController supprime la page précédente de la pile, respectivement, lorsque vous y revenez - elle est mise à jour, les méthodes ionViewWillEnter et ngOnInit fonctionnent, et vous pouvez appeler à nouveau la logique et mettre à jour les informations sur les pages, par exemple.
  2. Oubliez les anciennes méthodes push (), setRoot () et pop (), ainsi que la navigation dans les éléments de classe. Après tout, c'est ce qui a créé beaucoup de problèmes. NavCtrl a maintenant mis à jour les méthodes, qui passent le même chemin que dans les méthodes du routeur.

Il y a une mise en garde, où faire sans "MAIS" :)

Si nous ajoutons un gestionnaire d'événements au bouton matériel «retour» sur l'androïde et dans ce gestionnaire nous essayons d'aller quelque part en utilisant Router ou navController, alors nous obtenons l'erreur suivante dans la console: «Navigation déclenchée en dehors de la zone angulaire».

Oui, la navigation fonctionnera, la page s'ouvrira, mais rien ne fonctionnera dessus - ni l'initialisation des propriétés, ni les méthodes du cycle de vie. Malheureusement, la navigation en appuyant sur le bouton de retour est déclenchée en dehors de la zone angulaire et, en fait, ouvre uniquement le modèle: sans lier les variables au modèle, sans fonctions, crochets, méthodes de cycle de vie - sans rien.

En fait, la solution est très simple. Nous forçons simplement explicitement la navigation à l'intérieur de la zone angulaire.

Un exemple:

import { Component, NgZone } from '@angular/core'; import { NavController } from '@ionic/angular'; @Component({ selector: 'app-root', templateUrl: 'app.component.html' }) export class AppComponent { constructor(private navCtrl: NavController, private ngZone: NgZone){} this.ngZone.run(() => this.navCtrl.navigateForward('menu')).then();  this.ngZone.run(() => this.router.navigateByUrl('/menu/my-orders')).then(); } 

Et maintenant, tout fonctionne bien!

Il existe de nombreux articles intéressants sur ngZone, je vous conseille de les lire. Bonne chance!

Un peu sur les méthodes de navController:



  • this.navCtrl.setDirection ('root') - définit la page racine de la pile, en supprimant toutes les précédentes.
  • this.navCtrl.navigateRoot ('homePage') - similaire à navCtrl.setDirection ('root') + router.navigateByUrl ('homePage'), mais avec la suppression obligatoire de la page précédente de la pile (c'est ce dont nous avons besoin).
  • this.navCtrl.navigateForward ('examplePage') - similaire à router.navigateByUrl ('/ examplePage), mais avec une indication explicite où aller + peut supprimer la page précédente de la pile.
  • this.navCtrl.back () - similaire à location.back (), mais avec animation.
  • this.navCtrl.navigateBack ('backPage') - similaire à navCtrl.setDirection ('back') + router.navigateByUrl ('backPage').

Supposons que nous soyons maintenant sur le menu / page1,

image

et nous avons une pile de menus séparée et, après être passé de menu / page1 à la page de connexion, nous devons supprimer la page menu / page1 afin qu'après y être revenu, nous aurons une sorte de logique travaillant sur ngOnInit ou ionViewWillEnter. Si nous utilisons router.navigateByUrl ('login) pour la transition, après cela, nous serons sur la page de connexion, mais nous aurons également une page de menu,



en conséquence, après le passage de la connexion au menu / page1, ni ngOnInit ni ionViewWillEnter ne fonctionneront.

Si vous utilisez notre navCtrl.navigateRoot («connexion») pour naviguer, puis après avoir ouvert la page de connexion, la page précédente est supprimée. Et les méthodes ngOnInit et ionViewWillEnter fonctionneront.



C'est la beauté de l'utilisation de navController - le comportement attendu est parfaitement cohérent avec le courant .

Source: https://habr.com/ru/post/fr473488/


All Articles