🛣️

[Flutter]go_routerで「現在表示されている画面」を確認するためには

2024/12/26に公開

Flutterのgo_routerライブラリを使用しているときに、「現在画面上に表示されている画面」のルーティングを確認したくなったので、その実現方法を記録します

調べるきっかけ

確認したくなったきっかけを具体例を交えて説明したいと思います。

特定のGoRouterを下記のような階層構造で定義したとします。

app_router.dart
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()などのgoPage2に遷移すると、スタックとしては以下のようにHomeもPage1も積み上がります。

ページスタック(上)
Page2
Page1
Home

このとき、Page1は内部的にはビルドされています。
このビルドの仕組みによって、例えば GoogleAnalytics などで画面表示されたことをログイベントとして保存している場合、ログの取得をbuild()メソッドに仕込んでいると予期しないタイミングでログ取得されることになります。
ロギングの仕組みを変更したり、画面遷移をPushで実現すれば回避できると思いますが、以下理由から避けました

  • ロギングの仕組みの変更 → 全体に影響があるので修正コストが高い
  • 画面遷移をPushで実現 → 様々な箇所から画面呼び出しされていることや、pop()に影響が生じる

実現方法

go_routerに似たような悩みのissueがありました。
https://github.com/flutter/flutter/issues/129833

こちらの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

この判定自体は、スタックする可能性があるページに仕込めばいいので、全てのページに仕込む必要はないと思います。
もし全てのページに仕込む場合はもう少し汎用的にプロパティとして用意したりするのがいいと思います。

最後に

思ったより簡単に判定自体はできたのですが、このメソッドをいろいろな場所に散りばめることには少し抵抗があるのでもう少しいい方法ないかなあと思っています🤔

参考

https://qiita.com/dowa/items/291f95b20f7c738bcc83
https://github.com/flutter/flutter/issues/129833

ENECHANGE

Discussion