GoRouter
感想
新規に導入する分には使って良さそう、既存から移行もいけるだろうけどちょっと大変かも
pathがStringだけなのが地味に辛い、型付きルーティングを待つべきか悩ましい
refreshListenableはProvider/Riverpodとの相性が良さそう
Navigator2.0からの移行はページ遷移管理のControllerをGoRouterに書き換えが必要そう
宣言的ルーティング
パラメータの大文字小文字はそのままロケーション名に反映されますが、path との照合はケース・インセンシティブ(大文字小文字を区別しない)方式で行われます。
パラメータ限定の話?
path: '/hoge' != path: '/hOgE' であってほしい
pathに関して完全一致なはず、nameに関しては 'huga' == 'HUGA' になる
state.errorはExceptionが渡せるからエラーハンドリングに上手く使えそう
GoRouter(errorBuilder: があった。わざわざ別ページに飛ばすことあるかな?
ダイアログ出してpopが常套手段だと思っていた
Deep Linkの設定は新規開発だと忘れそう
ナビゲーション
自動でファイル参照は入らないなかったので GoRouter.of(context).goを使うことになりそう
GoRouterで参照つける→GoRouter消す→context.go書くならインテリセンス効くけどcontext.go一発では入らなかった
goとpushの違い
'/'から'/go/to/page/'を例として、
go
goページ、toページ、pageページが順番にスタックされる
page
最後のpageページだけが/の下にスタックされる?
ディープリンクを使うとinitalLocationは無視される
GoRouterはChangeNotifier
extraはウェブアプリ向けでは非推奨
ブラウザの戻るで戻るとオブジェクトが消えるらしい
サブルート
routesでWidgetのchildスタックみたいなことができる
サンプルがFamiliesでRiverpodと被るなあと思ったけど予約語じゃなかった。Familyデータがあるという仮定の話だった
リダイレクト
code:dart
// ユーザーがログインしていない場合はログインページにリダイレクト
redirect: (state) {
final loggedIn = loginInfo.loggedIn;
final goingToLogin = state.location == '/login';
// ユーザーがログインしておらず、かつ /login に向かっていない場合はログインが必要
if (!loggedIn && !goingToLogin) return '/login';
// ユーザーがログイン済みで、かつ /login に向かっている場合はログイン不要
if (loggedIn && goingToLogin) return '/';
// 一切リダイレクトが不要な場合
return null;
},
ログインしていなかったらログインページにリダイレクトは便利そう
これなしだとページのあちこちでログインしているかを判定する必要があって、だぶり・もれが出てしまう
code:dart
GoRouter(
...
// listenable に変化があればルータによってルートがリフレッシュされる
refreshListenable: loginInfo,
loginInfoが変わるとGoRouterのリダイレクト判定が走るらしい
これも使いそう。そして忘れそう
ProviderでいけるならRiverpodでも指定できるはず
GoRouterRefreshStreamでラップすることでstream も渡すことができるみたい
BLoCが例に挙げられていたし使うことはないかも?
code:dart
onPressed: () {
// ユーザーをログインさせてリスナーに通知
context.read<LoginInfo>().login('test-user');
// loginInfo があるので、/login から / へルータが自動的にリダイレクト
//context.go('/');
},
↑良すぎる。コードもスッキリだし遷移に関するコードがRouteにまとまっているのがみやすくてとても良い
redirectの呼び出しについて
redirectがない
builderが必要
redirectがnullを返す可能性がある
builderも必要
redirectが必ずString
builderは不要 (トップレベル以外でredirect書くと無視される)
redirectLimitが指定されている (デフォルト 5)
連続したリダイレクトはバグの可能性が高いため
redirectループに注意
詳細は読者の演習とする
an exercise that I'll leave to the reader
久しぶりにこの言い回し見た
loginFromもstateに渡せるからログ取りにも使えそう
名前付きルート
pathだけでなくnameも指定できる
nameにenumなりFreezedなりのtoStringを渡せばハードコーディングなしでいけそう
パラメータ、リダイレクトも可能
URLパス・ストラテジー
webとしてデプロイする時の話
デフォルトだとURLに#がつくけどGoRouterだと簡単に外せる
URLがindex.htmlに紐づくようにしないとルーティングできないらしい (あまり内容がわからず)
ルートのデバッグ
code:dart
debugLogDiagnostics: true,
ルーティング中の情報を出力してくれる
いつかお世話になる時が来るかもしれない
トランジション効果
builder, errorBuilderの代わりにpageBuilder, errorPageBuilderを使うとHogeTransitionPageでPageをラップして遷移効果を付与できる
この辺りはNavigator1.0と同様な感じがする
NoTransitionPageのようによく使うCustomTranstionはクラスとして作ることができる?
できるであればボイラプレートになってしまうから作りたい
Transtionのkeyを同じにすることで同じkey間の遷移には効果が付かないようにできる
タブ移動のページとかで、タブ遷移の効果がつくからTransition効果はpush,popの時だけ欲しいときに使える
非同期データ
idを渡して遷移先のページで取得する
Riverpodとかでもやっている手法
パラメータの使い方でGoRouterが何かサポートしているわけではなさそう
ネストナビゲーション
タブとかの画面ない遷移でlocationも変わる
ディープリンクが可能になる
URLをenumでやるには辛いだろうからやはりFreezedか
StateFulWidgetにしてAutomaticKeepAliveClientMixinをつけようね
Web以外だと使う場面が限られてくるかも(Riverpodで代替できそう)
Navigatorビルダー
navigatorBuilder:でMaterialAppとNavigatorの間(よくProviderを置く層)にWidgetをおける
複数ページに適用できるオーバーレイとしても機能できる
Navigatorとの併用
Navigator.push, Navigator.popが動作する
Navigator.pushだとアドレス更新ができない(Web)
GoRouterで代替できる
新規画面を呼び出す側がナビゲーションの結果を受け取ることができないのであれば、新規画面側でユーザーによる入力を処理すればいいのです
確かに
新規登録の場面に限らず、この発想の転換は活かせる場所がありそう
一緒に使ってはいけない場面はないけど、状態管理とリビルドに気をつけて使う
ウェブ履歴
Router.reglectでブラウザに履歴を残さずに遷移できる
GoRouter(routerNeglect: true,.. でアプリ全体で残さないようにもできる
ブラウザの戻るボタンには影響する
多分履歴がのこっているひとつ前に戻る?
型付けルーティングの提案
まだWIP
name: 'family' から pushFamily, goFamilyメソッドが自動生成されるもの
context.go('familyyyy') とかで実行時エラーにならなくなるからとても良い
コード生成は初めは build_runner, マクロが来たら移行する