Ionicには画面遷移を実現する方法が複数用意されていて、Ionic3と4で似ている部分や変わった部分もあります。自分の場合、仕事の都合でIonic3に慣れ始めてからIonic4へ乗り換えたため、違いや使い分けが分からず実装に一貫性がなくなってしまうこともありました。(作り直したい……。)
この記事では、Ionic4の画面遷移まわりの機能の種類や、どういった意図でそれらを使い分けると良いのか、現時点での考えを記載します。
ion-router-outlet
とNavController
- ion-router-outlet - Ionic Documentation
- Angular Navigation - Ionic Documentation
- Using Angular Routing with Ionic 4 | joshmorony - Learn Ionic & Build Mobile Apps with Web Tech
- ionic/nav-controller.ts at master · ionic-team/ionic
Angular版のIonicで推奨されている画面遷移の機能です。
Angular Routingと統合されており、URLベースの画面遷移を提供します。使い方はAngularのrouter-outlet
とほぼ同じですが、Ionic独自の拡張がされています。
HTML側からはa要素のrouterLink
属性、TypeScript側からはNavController
クラスを使って遷移を制御します。
このNavController
はIonic3のNavController
とは別物で、メソッド名や引数も変わっています。
ナビゲーションスタック
ion-router-outlet
での画面遷移にはIonic独自のナビゲーションスタックの概念があります。この概念はIonic3と4でほぼ変わりません。
ナビゲーションスタックは画面遷移の履歴をキャッシュする仕組みのようなもので、ナビゲーションスタックに追加された画面は次の画面に遷移してもコンポーネントのインスタンスが維持されます。この挙動は通常のAngularとは違うので注意が必要です。
- IonicはナビゲーションしてもngOnDestoryが呼ばれない! - Qiita
- Ionic 4 and the Lifecycle Hooks in Angular - Paul Stelzer - Medium
次の画面へ進む機能・使い分け
-
NavConrtroller
のnavigateForward()
で遷移する場合、ナビゲーションスタックに現在までの画面を残したまま次の画面コンポーネントを表示します。デフォルトでは次へ遷移するアニメーションが発生します。-
routerLink
にrouterDirection
を指定しない、又はrouterDirection="forward"
を指定した場合も同じ挙動になります。
-
-
NavConrtroller
のnavigateRoot()
で遷移する場合、これまでのナビゲーションスタックを破棄して、次の画面から新規のナビゲーションスタックを開始します。デフォルトではアニメーションは発生しません。-
routerLink
にrouterDirection="root"
を指定した場合も同じ挙動になります。
-
使い分けは、
- 一般的な画面遷移では
navigateFoward()
- ナビゲーションスタックをリセットしたい場合は
navigateRoot()
となります。一般的なnavigateForward()
は、次の画面に進んでもコンポーネントのインスタンスが残り続けることを必ず意識しましょう。
前の画面へ戻る機能・使い分け
前へ戻るためのメソッドでは、微妙に機能が違うものが複数提供されています。全てのメソッドで、デフォルトでは前へ遷移するアニメーションが発生します。
-
NavController
のpop()
で遷移する場合は、ナビゲーションスタックの直前の画面へ戻り、今見えている画面はナビゲーションスタックから破棄されます。 -
NavConrtroller
のnavigateBack()
で遷移する場合は、引数で指定された画面がナビゲーションスタックに含まれている場合、それよりも後のナビゲーションスタックは破棄されます。-
routerLink
にrouterDirection="back"
を指定した場合も同じ挙動になります。
-
-
NavController
のback()
で遷移する場合は、AngularのLocation.back()
と同じ挙動になります。
使い分けとしては以下のようになります。
- コンテクストに応じて前の画面に戻したい場合は
pop()
- コンテクストに関係なく特定の画面に戻したい場合は
navigateBack()
- ブラウザのバックボタンと同じ挙動で前に戻したい場合は
back()
パラメータの渡し方
Angular Routerと同じ方法で遷移先の画面へパラメータを渡せます。
https://angular.jp/guide/router
ion-modal
とModalController
ion-modal
は、見えている画面の上に別のコンポーネントを重ねて表示する機能で、ion-modal
の生成・表示・非表示を制御するのがModalController
です。
特にスマートフォンサイズの場合、MaterialDesignテーマではion-router-outlet
による遷移と見た目としてはほぼ同じ効果が起こります。しかし、ルーティングによる画面遷移と意味合いは異なります。
ルーティングによる画面遷移との違い・使い分け
ion-router-outlet
を使ったルーティングによる画面遷移ではURLが変化します。また、遷移中のアニメーションが終了した後は、遷移前後の画面を同時に表示することが想定されていません。
一方ion-modal
でコンポーネントを表示する場合は、既存の画面表示とURLを維持したまま、単純にその上へ新しいコンポーネントを重ねて表示します。表示の制御もルーティングとは独立しており、またion-modal
単体で複数のコンポーネントを切り替えて表示する機能はありません。
そのため、ion-router-outlet
との使い分けは次のようになります。
-
ion-modal
を使う場合- コンポーネントを重ねて同時に表示したい
- フォームの入力を補助する半モーダルを出したい
- タブレット用アプリで一次的に子画面的なものを出したい
- ルーティングへ影響を与えず、一次的に別の画面を表示したい
- コンポーネントを重ねて同時に表示したい
- それ以外は
ion-router-outlet
を使う
パラメータの渡し方
...
public async createModal(): void {
const modal = await this.modalCtrl.create({
component: ChildComponent,
componentProps: { id: this.id }, // *A
});
await modal.present();
const { data } = await modal.onDidDismiss(); // *b
console.log(data.result);
}
@Component({...})
export class ChildComponent {
@Input() public id: string; // *a
constructor(
private modalCtrl: ModalController
) {
}
public close(): void {
this.modalCtrl.dismiss({ result: 'success' }); // *B
}
}
モーダルの生成元からモーダル内部へのデータの引き渡し
componentProps
というキーでオブジェクトを渡すと、モーダル内部の同名のプロパティへ自動的に引き渡されます。(*A, *a部)
モーダル内部からモーダル生成元へのデータの引き渡し
モーダル内部からModalController
のdismiss()
へ引数として渡したデータを、モーダル生成側のコンポーネントからはonDidDismiss()
かonWillDissmiss()
で非同期で受け取れます。(*B, *b部)
ion-nav
ナビゲーションスタックを持ち、ion-router-outlet
と似た画面遷移の機能を提供します。しかし、ルーターとしての機能はなくルーティングには影響しません。
Ionic3のion-nav
やNavController
とよく似ていますが、Ionic4のAngular版であえてion-nav
を使うべき状況は限定的だと思われます。
ion-modal
の内部で画面遷移をさせたい場合はion-nav
を組み合わせて使うことになります。
// ion-navの使い方についてはあとで追記したいです…。
終わりに
表面的な挙動としては似ているところもあるion-router-outlet
、ion-modal
、ion-nav
ですが、全て実装方法が違うので、ある実装のために作ったコンポーネントを別の実装に使いまわそうとしてもできなかったりします。
特別な要件がなければion-router-outlet
での画面遷移に寄せるべきでしょう。
ドキュメントだけでは分からない部分も多いので、ググっても見つからない部分はGitHubのソースコードを読みに行くのが良さそうです。