Navegação entre plataformas: por que o NavController derrotou o angular / roteador no Ionic 4



Olá pessoal! Meu nome é Nikita Zhigamovsky, programadora da KitApp, e quero falar sobre minha experiência na construção de navegação no Ionic 4: o problema que encontrei e sua solução.

Desenvolvo soluções multiplataforma para aplicativos móveis desde 2018. Eu trabalhava na terceira versão do Ionic, mas, com o passar do tempo, a funcionalidade está se desenvolvendo, decidi mudar para uma versão mais recente, e os momentos e bugs irritantes do modelo anterior no Ionic 4 parecemter sido corrigidos.

Parece que o que poderia dar errado. Finalmente, temos a funcionalidade de um roteamento Angular normal, e não o antigo NavController com todas as suas deficiências. Mesmo no site oficial da Ionic, o guia de roteamento indica que vale a pena navegar pelas páginas de maneira programática usando os métodos angular / roteador. Mas havia algo que me fez voltar ao antigo NavController.

A essência do problema


Um bug interessante foi notado. Suponha que você tenha um menu lateral, você o criou usando o painel de divisão de íons. Você também tem páginas separadas no menu e deseja ir delas para outras páginas que estão no menu. Navegue usando Router.navigateByUrl ('/ menu / ...'). Em seguida, chamamos a página de menu A e a página é separada do menu - B. Mas há uma MAS!

Suponha que, na página A, uma certa lógica seja acionada no evento ngOnInit. Você navega para a página B usando o roteador e percebe que a página do menu ainda está ativa - ela não foi excluída. Portanto, se você voltar à página A, o evento ngOnInit não funcionará, pois o evento ngOnDestroy desta página não funcionou. Parece que tudo é lógico. Nesses momentos, eles geralmente recorrem a um dos métodos do ciclo de vida, não o angular, mas o ionic - ionViewWillEnter. É acionado quando você acessa a página assim que se torna ativa. Tudo parece estar bem, se encaixa perfeitamente, mas há um certo número de convenções.

Nenhuma das opções para uma ação adequada na página A funcionará ao acessá-la, se essa transição não for das páginas que estão no menu. Você não poderá acompanhar a transição para esta página, porque, repito, ainda está aberta e funciona silenciosamente em outras páginas, por exemplo, na página B.

Alguns exemplos ilustrativos:

ionViewWillEnter funcionará se você tiver a seguinte estrutura de página:

1) Páginas separadas

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

Neste exemplo, o ionViewWillEnter funcionará perfeitamente em todas as páginas. (página1 => página2, página2 => página3 etc.)

2) Menu / Guias

- menu
- menuPage1
- menuPage2
- menuPage3
Neste exemplo, tudo ficará bem: o método ionViewWillEnter será acionado toda vez que você for a qualquer uma das páginas (menuPage1 => menuPage2, menuPage1 => menuPage3, etc.).

Mas no exemplo abaixo, tudo é mais complicado:

- menu
- menuPage1
- menuPage2
- menuPage3
- loginPage
- inscrição

É aqui que começam os problemas do roteamento angular padrão. Ao navegar dentro das páginas do menu (menuPage1 => menuPage2 => menuPage3) - o método ionViewWillEnter funcionará como de costume, da mesma maneira ao navegar entre páginas individuais (loginPage => signupPage). Mas assim que começamos a mover-se entre páginas separadas e páginas de menu (loginPage => menu / menuPage1 ou menu / menuPage3 => signupPage), nem o método ngOnInit nem o ionViewWillEnter funcionam. O ngOnInit não funcionará porque a página não foi destruída, o que é lógico. Mas por que o ionViewWillEnter não funcionou?

Com base na documentação, o ionViewWillEnter trabalha em pilhas de roteamento separadas (a palavra-chave “individual”) ou entre páginas individuais ou em menus / guias. Mas não na estrutura mista de páginas e menus / guias individuais. Estranho, mas isso é considerado comportamento normal. Ao mesmo tempo, esse não é exatamente o comportamento que os usuários esperam, especialmente quando você considera o nome dos ganchos do ciclo de vida :).

Então, como resolver esse problema?


Tendo visitado muitos fóruns, mas não tendo visto uma solução normal, e tendo visto alguns hacks duvidosos que nem sempre funcionam, fica claro que algo é necessário. Algo que mudará a funcionalidade de transição entre páginas de qualquer tipo.

O que fazer neste caso? É claro, jogue o roteador no inferno e esqueça-o, porque ainda existe o nosso NavController anteriormente odiado e agora tão bom.

A principal diferença entre o método NavController.navigateRoot () é que, após mudar para outra página, a anterior é automaticamente destruída! E quando você alternar novamente, o método ngOnInit e o ionViewWillEnter funcionarão! De fato - esta é a solução perfeita - sem muletas e funções auto-escritas duvidosas.

O mais legal é que ele funciona com qualquer estrutura de página: mesmo entre normal, mesmo dentro do menu, e até misto, como no exemplo anterior.

Resuma os aspectos positivos:

  1. O NavController exclui a página anterior da pilha, respectivamente, quando você voltar a ela - ela é atualizada, os métodos ionViewWillEnter e ngOnInit funcionam e você pode chamar a lógica neles novamente e atualizar as informações nas páginas, por exemplo.
  2. Esqueça os métodos antigos push (), setRoot () e pop (), além de navegar pelos elementos da classe. Afinal, foi isso que criou muitos problemas. Agora, o navCtrl atualizou os métodos, que passam pelo mesmo caminho dos métodos do roteador.

Há uma ressalva, onde fazer sem "MAS" :)

Se adicionarmos um manipulador de eventos ao botão "voltar" do hardware no android e nesse manipulador tentarmos ir a algum lugar usando o roteador ou o navController, obteremos o seguinte erro no console: 'Navegação acionada fora da zona angular'.

Sim, a navegação funcionará, a página será aberta, mas nada funcionará nela - nem a inicialização das propriedades, nem os métodos do ciclo de vida. Infelizmente, a navegação pressionando o botão Voltar é acionada fora da zona Angular e, de fato, abre apenas o modelo: sem vincular variáveis ​​ao modelo, sem funções, ganchos, métodos de ciclo de vida - sem nada.

A solução é muito simples, na verdade. Simplesmente forçamos explicitamente a navegação dentro da zona Angular.

Um exemplo:

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

E agora tudo funciona bem!

Existem muitos artigos interessantes sobre o ngZone, aconselho você a ler. Boa sorte

Um pouco sobre os métodos navController:



  • this.navCtrl.setDirection ('root') - define a página raiz na pilha, excluindo todas as anteriores.
  • this.navCtrl.navigateRoot ('homePage') - semelhante ao navCtrl.setDirection ('root') + router.navigateByUrl ('homePage'), mas com a remoção obrigatória da página anterior na pilha (é disso que precisamos).
  • this.navCtrl.navigateForward ('examplePage') - semelhante ao router.navigateByUrl ('/ examplePage), mas com uma indicação explícita de onde ir + pode excluir a página anterior da pilha.
  • this.navCtrl.back () - semelhante ao location.back (), mas com animação.
  • this.navCtrl.navigateBack ('backPage') - semelhante ao navCtrl.setDirection ('back') + router.navigateByUrl ('backPage').

Suponha que agora estamos no menu / página1,

imagem

e temos uma pilha de menus separada e, depois de passar do menu / página1 para a página de login, precisamos excluir a página do menu / página1 para que, depois de mudar para ela novamente, tenhamos algum tipo de lógica trabalhando em ngOnInit ou ionViewWillEnter. Se usarmos router.navigateByUrl ('login) para a transição, depois estaremos na página de login, mas também teremos uma página de menu,



consequentemente, após alternar do login para o menu / página1, nem o ngOnInit nem o ionViewWillEnter funcionarão.

Se você usar o navCtrl.navigateRoot ('login') para navegar, depois de abrir a página de login, a página anterior será excluída. E os métodos ngOnInit e ionViewWillEnter funcionarão.



Essa é a beleza de usar o navController - o comportamento esperado é totalmente consistente com o atual .

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


All Articles