[Flutter]go_routerで「現在表示されている画面」を確認するためには
Flutter のgo_routerライブラリを使用しているときに、「現在画面上に表示されている画面」のルーティングを確認したくなったので、その実現方法を記録します
調べるきっかけ
確認したくなったきっかけを具体例を交えて説明したいと思います。
特定の GoRouter を下記のような階層構造で定義したとします。
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const Home(),
routes: [
GoRoute(
name: 'page1'
path: 'page1',
builder: (context, state) => const Page1(),
routers: [
GoRoute(
name: 'page2'
path: 'page2',
builder: (context, state) => const Page2(),
)
]
),
]
),
],
);
このとき、context.go()やcontext.goNamed()などのgoでPage2に遷移すると、スタックとしては以下のように Home も Page1 も積み上がります。
| ページスタック(上) |
|---|
| Page2 |
| Page1 |
| Home |
このとき、Page1 は内部的にはビルドされています。
このビルドの仕組みによって、例えば GoogleAnalytics などで画面表示されたことをログイベントとして保存している場合、ログの取得をbuild()メソッドに仕込んでいると予期しないタイミングでログ取得されることになります。
ロギングの仕組みを変更したり、画面遷移を Push で実現すれば回避できると思いますが、以下理由から避けました
- ロギングの仕組みの変更 → 全体に影響があるので修正コストが高い
- 画面遷移を Push で実現 → 様々な箇所から画面呼び出しされていることや、
pop()に影響が生じる
実現方法
go_router に似たような悩みの issue がありました。
こちらの issue でLike が多かった投稿を元に、GoRouteに「現在表示されているページが自身かどうか」を判定する Extension を作りました。
import 'package:go_router/go_router.dart';
extension GoRouterExtension on GoRouter {
bool isCurrentLocation(final String routePath) {
final RouteMatch lastMatch = routerDelegate.currentConfiguration.last;
final RouteMatchList matchList = lastMatch is ImperativeRouteMatch
? lastMatch.matches
: routerDelegate.currentConfiguration;
final String location = matchList.uri.toString();
return location.endsWith(routePath);
}
}
これを以下のように呼び出すことで判定可能です
GoRouter.of(context).isCurrentLocation('page1')
例で紹介した、GoRoute.routes[]で定義した下層の Page2 を呼び出した場合に、各画面にisCurrentLocation()を定義していたらこのような結果になります。
| ページスタック(上) | isCurrentLocation() |
|---|---|
| Page2 | true |
| Page1 | false |
| Home | false |
この判定自体は、スタックする可能性があるページに仕込めばいいので、全てのページに仕込む必要はないと思います。
もし全てのページに仕込む場合はもう少し汎用的にプロパティとして用意したりするのがいいと思います。
最後に
思ったより簡単に判定自体はできたのですが、このメソッドをいろいろな場所に散りばめることには少し抵抗があるのでもう少しいい方法ないかなあと思っています 🤔
参考
ENECHANGEグループは、「エネルギー革命」を技術革新により推進し、より良い世界を創出することをミッションとするエネルギーベンチャー企業です。 enechange.co.jp/
Discussion