Navegación multiplataforma: por qué NavController derrotó a angular / router en Ionic 4



Hola a todos! Mi nombre es Nikita Zhigamovsky, programador de KitApp, y quiero hablar sobre mi experiencia en la construcción de navegación en Ionic 4: el problema que encontré y su solución.

He estado desarrollando soluciones multiplataforma para aplicaciones móviles desde 2018. Solía ​​trabajar en la tercera versión de Ionic, pero, a medida que pasa el tiempo, la funcionalidad se está desarrollando, decidí cambiar a una versión más nueva, y los molestos momentos y errores del modelo anterior en Ionic 4 ya se han solucionado.

Parecería que lo que podría salir mal. Finalmente, tenemos la funcionalidad de un enrutamiento angular normal, y no el antiguo NavController con todas sus deficiencias. Incluso en el sitio web oficial de Ionic, la guía de enrutamiento indica que vale la pena navegar por las páginas mediante programación utilizando los métodos angulares / enrutadores. Pero había algo que me hizo volver al antiguo NavController.

La esencia del problema


Se notó un error interesante. Supongamos que tiene un menú lateral, lo hizo usando ion-split-pane. También tiene páginas separadas del menú y desea pasar de ellas a otras páginas que están en el menú. Navegue usando Router.navigateByUrl ('/ menu / ...'). Luego, llamamos a la página del menú A, y la página separada del menú - B. ¡Pero hay una PERO!

Supongamos que, en la página A, se activa una cierta lógica en el evento ngOnInit. Navega a la página B con el enrutador y observa que la página del menú todavía está activa, no se ha eliminado. En consecuencia, si vuelve a la página A, el evento ngOnInit no funcionará, ya que el evento ngOnDestroy de esta página no funcionó. Parece que todo es lógico. En esos momentos, generalmente recurren a uno de los métodos del ciclo de vida, no el angular, sino el iónico: ionViewWillEnter. Se dispara cuando va a la página tan pronto como se activa. Todo parece estar bien, encaja perfectamente, pero hay un cierto número de convenciones.

Ninguna de las opciones para una acción adecuada en la página A funcionará cuando vaya a ella, si esta transición no es de páginas que están en el menú. No podrá realizar un seguimiento de la transición a esta página porque, repito, todavía está abierta y funciona silenciosamente en otras páginas, por ejemplo, en la página B.

Algunos ejemplos ilustrativos:

ionViewWillEnter funcionará si tiene la siguiente estructura de página:

1) páginas separadas

- página1
- página2
- página3

En este ejemplo, cuando voy a cada página, ionViewWillEnter funcionará perfectamente. (página1 => página2, página2 => página3, etc.)

2) Menú / Pestañas

- menú
- menuPage1
- menuPage2
- menuPage3
En este ejemplo, todo estará bien: el método ionViewWillEnter se activará cada vez que vaya a cualquiera de las páginas (menuPage1 => menuPage2, menuPage1 => menuPage3, etc.).

Pero en el ejemplo a continuación, todo es más complicado:

- menú
- menuPage1
- menuPage2
- menuPage3
- loginPage
- página de registro

Aquí es donde comienzan los problemas del enrutamiento angular estándar. Al navegar dentro de las páginas del menú (menuPage1 => menuPage2 => menuPage3): el método ionViewWillEnter funcionará como de costumbre, de la misma manera cuando se navega entre páginas individuales (loginPage => signupPage). Pero tan pronto como comenzamos a movernos entre páginas separadas y páginas de menú (loginPage => menu / menuPage1 o menu / menuPage3 => signupPage), ni el método ngOnInit ni ionViewWillEnter funcionan. ngOnInit no funcionará porque la página no ha sido destruida, lo cual es lógico. Pero, ¿por qué no funcionó ionViewWillEnter?

Según la documentación, ionViewWillEnter funciona dentro de pilas de enrutamiento separadas (la palabra clave "individual") o entre páginas individuales, o dentro de menús / pestañas. Pero no en la estructura mixta de páginas individuales y menús / pestañas. Extraño, pero esto se considera comportamiento normal. Al mismo tiempo, este no es exactamente el comportamiento que los usuarios esperan, especialmente cuando se considera el nombre de los ganchos del ciclo de vida :).

Entonces, ¿cómo resolver este problema?


Después de haber visitado muchos foros, pero no haber visto una solución normal y haber visto algunos trucos de vida dudosos que no siempre funcionan, queda claro que se necesita algo más. Algo que cambiará la funcionalidad de transición entre páginas de cualquier tipo.

¿Qué hacer en este caso? Por supuesto, lanza el Router al infierno y olvídate de él, porque todavía existe nuestro NavController odiado y ahora tan bueno.

La principal diferencia entre el método NavController.navigateRoot () es que después de cambiar a otra página, ¡la anterior se destruye automáticamente! Y cuando lo cambies de nuevo, ¡tanto el método ngOnInit como ionViewWillEnter funcionarán! De hecho, esta es la solución perfecta, sin muletas y dudosas funciones autoescritas.

Lo mejor es que funciona con cualquier estructura de página: incluso entre normal, incluso dentro del menú, incluso de tipo mixto, como en el último ejemplo.

Resuma los aspectos positivos:

  1. NavController elimina la página anterior de la pila, respectivamente, cuando vuelve a ella: se actualiza, los métodos ionViewWillEnter y ngOnInit funcionan, y puede llamar a la lógica en ellos nuevamente y actualizar la información en las páginas, por ejemplo.
  2. Olvídate de los viejos métodos push (), setRoot () y pop (), así como navegar por los elementos de la clase. Después de todo, esto fue lo que creó muchos problemas. Ahora navCtrl ha actualizado los métodos, que pasan la misma ruta que en los métodos del enrutador.

Hay una advertencia, donde prescindir de "PERO" :)

Si agregamos un controlador de eventos al botón de "atrás" del hardware en el Android y en este controlador tratamos de ir a algún lugar usando Router o navController, obtenemos el siguiente error en la consola: 'Navegación activada fuera de la zona angular'.

Sí, la navegación funcionará, la página se abrirá, pero nada funcionará en ella, ni la inicialización de las propiedades, ni los métodos del ciclo de vida. Desafortunadamente, la navegación presionando el botón Atrás se activa fuera de la zona angular y, de hecho, abre solo la plantilla: sin vincular variables a la plantilla, sin funciones, ganchos, métodos de ciclo de vida, sin nada.

La solución es muy simple, en realidad. Simplemente forzamos explícitamente la navegación dentro de la zona angular.

Un ejemplo:

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(); } 

¡Y ahora todo funciona bien!

Hay muchos artículos interesantes sobre ngZone, le aconsejo que lea. Buena suerte

Un poco sobre los métodos de navController:



  • this.navCtrl.setDirection ('root'): establece la página raíz en la pila, eliminando todas las anteriores.
  • this.navCtrl.navigateRoot ('homePage') - similar a navCtrl.setDirection ('root') + router.navigateByUrl ('homePage'), pero con la eliminación obligatoria de la página anterior en la pila (que es lo que necesitamos).
  • this.navCtrl.navigateForward ('examplePage') - similar a router.navigateByUrl ('/ examplePage), pero con una indicación explícita de dónde ir + puede eliminar la página anterior en la pila.
  • this.navCtrl.back (): similar a location.back (), pero con animación.
  • this.navCtrl.navigateBack ('backPage') - similar a navCtrl.setDirection ('back') + router.navigateByUrl ('backPage').

Supongamos que ahora estamos en menu / page1,

imagen

y tenemos una pila de menú separada y, después de pasar del menú / página1 a la página de inicio de sesión, necesitamos eliminar la página menú / página1 para que después de cambiar de nuevo, tengamos algún tipo de lógica trabajando en ngOnInit o ionViewWillEnter. Si usamos router.navigateByUrl ('inicio de sesión) para la transición, luego estaremos en la página de inicio de sesión, pero también tendremos una página de menú,



en consecuencia, después de cambiar de inicio de sesión a menu / page1, ni ngOnInit ni ionViewWillEnter funcionarán.

Si utiliza nuestro navCtrl.navigateRoot ('inicio de sesión') para navegar, luego de abrir la página de inicio de sesión, se elimina la página anterior. Y los métodos ngOnInit e ionViewWillEnter funcionarán.



Esta es la belleza de usar navController: el comportamiento esperado es totalmente consistente con el actual .

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


All Articles