こんにちは。クライアントグループの上原です。 StudyplusのFlutterアプリでの開発には、go_routerが利用されています。 今回は、利用していて感じたどういう状況でどの方法を利用して画面遷移時にパラメーターを渡すのが良いのかを紹介します。 また、上記のやり方をgo_router_builderを利用して行った場合に、安全にデータをやり取りする方法も紹介します。
利用したFlutterのバージョンは、3.13.7
です。
利用したライブラリのバージョンは、下記になります。
ライブラリ名 | バージョン |
---|---|
go_router | 12.0.1 |
go_router_builder | 2.3.4 |
画面遷移時のパラメーターの渡し方について
go_routerでは、3つのやり方でパラメーターを次の画面へ渡すことができます。
パスパラメーター
パスの中に:パスパラメーター名
といった形で指定できます。
stateのpathParameters(Map<String, String>)にパスパラメーター名を利用してアクセスすることでパスに渡ってきた各パラメーターを取得できます。
下記例では、/book/detail/1
といったパスへアクセスが来た時にstate.pathParameters['bookId']
により1
が取得されBookScreenにbookId 1
を設定した画面が表示されるようになります。
final _router = GoRouter( routes: [ GoRoute( path: '/book/detail/:bookId', builder: (BuildContext context, GoRouterState state) { return BookScreen( bookId: state.pathParameters['bookId'], ); }, ), ], );
この渡し方を利用する場面としては、本が複数種類存在していてid
などで一意に定まるデータを取得する場面での利用が考えられます。
クエリパラメーター
state.uri.queryParameters(Map<String, String>)にクエリパラメーター名を利用してアクセスすることで渡ってきた各クエリパラメーターを取得できます。
下記例では、/book/search?query=title&order=desc
といったパスへアクセスが来た時にstate.uri.queryParameters['query']
によりtitle
が取得state.uri.queryParameters['order']
によりdesc
が取得されBookSearchScreenにquery:title
, order:desc
を設定した画面が表示されるようになります。
final _router = GoRouter( routes: [ GoRoute( path: 'book/search', builder: (BuildContext context, GoRouterState state) { final query = state.uri.queryParameters['query']; final order = state.uri.queryParameters['order']; return BookSearchScreen( query: query, order: order, ); }, ), ], );
この渡し方を利用する画面としては、上記の例のように、検索のオプションのようなデータを操作したものを取得したい場合に利用します。 クエリパラメーターの場合、クエリパラメーターが渡ってくるかどうかは分からないので基本的には、どれかが欠けていても問題ないようにすることが大事です。
Extraパラメーター
stateのextra(Object?)を利用しオブジェクトを渡すことでデータを取得できます。
下記例では、_tap
メソッドを叩くとBookオブジェクトを渡して/book
へ遷移します。
/book
パスへアクセスが来た時にstate.extra
をBookにキャストしてBookScreenに設定しています。
void _tap() => context.go( '/book', extra: Book( id: 1, title: 'タイトル', ), ); final _router = GoRouter( routes: [ GoRoute( path: '/book', builder: (BuildContext context, GoRouterState state) => BookScreen( book: state.extra! as Book, ), ), ], );
Extraパラメーターを利用すると様々な状況で便利にデータを渡すことが可能になります。 例えば、本の一覧画面から本のオブジェクトを本の詳細画面へ渡すことで、パスパラメーターでは、本のidを利用して本を取得していた箇所がオブジェクトをそのまま渡す形で置き換えることも出来るようになります。 しかし、便利な反面、オブジェクトを渡すことになるのでidを渡していた時にはなかった問題もあります。 遷移元がオブジェクトをきちんと保持していることが前提なので、ディープリンクなどの直接的な画面遷移には対応できません。 またWebでの利用を考えると、戻るボタンを押して前画面に戻った時や、リロードやURLの直打ちといった事例の際にオブジェクトを利用できない問題などもあります。 Studyplusでは、今後WebでFlutterを利用予定のためExtraパラメーターを利用せず、パスパラメーター、クエリパラメーターを利用しての画面遷移を行なっています。
go_router_builderを利用した型安全なパラメーターの渡し方
3つのパラメーターの渡し方を紹介しましたが、パスパラメーター・クエリパラメーターはStringでデータが渡され、ExtraパラメーターはObjectでデータが渡される形になっています。 しかし、上記の渡し方では、本来渡したいはずの型情報が抜け落ちており安全にパラメーターを渡して画面遷移を実現出来ているとは言えません。 安全にパラメーターを渡せていないとどうなるかというと下記コードを見てください。
GoRoute( path: '/book/detail/:bookId', builder: (BuildContext context, GoRouterState state) { final bookId = int.parse(state.pathParameters['bookId']!); return BookScreen( bookId: bookId, ); }, ),
この定義では、/book/detail/:bookId
の:bookId
がintを要求している状況です。
しかし、実際には、context.go('/book/detail/id1');
のようなコードが書けてしまいます。このコードを動かすとStringが渡りそれをintにパースしようとして失敗してしまうことになります。それを防ぐために、go_router_builderを利用します。
事前準備
Routeを定義するファイルでgo_router_builderで生成されるファイルを利用するためにpartで参照します。
import 'package:go_router/go_router.dart'; part 'this_file.g.dart';
GoRouterの定義部分のroutesを$appRoutes
に変更します。
final GoRouter router = GoRouter( debugLogDiagnostics: true, routes: $appRoutes, );
TypedGoRouteの定義
それでは、実際にRouteの定義をしていきます。/
配下にbook/detail/:bookId
を設定してTypedGoRoute
にBookDetailRoute
を設定します。
@TypedGoRoute<HomeRoute>( path: '/', routes: <TypedGoRoute<GoRouteData>>[ TypedGoRoute<BookDetailRoute>( path: 'book/detail/:bookId', ), ], ) // HomeRouteの定義は省いています。 class BookDetailRoute extends GoRouteData { const BookDetailRoute({ required this.bookId, }); final int bookId; @override Widget build(BuildContext context, GoRouterState state) => BookScreen( bookId: bookId, ); }
上記処理を書いた後にbuild_runnerを走らせます。
画面遷移をしたい時は下記のように、BookDetailRoute
を作成しpush
などの遷移をします。
onTap: () => const BookDetailRoute(bookId: 1).push(context)
go_router_builderを利用することで、安全に画面遷移時にパラメータを渡すことが出来るようになりました。
また、画面遷移時のパス設定の間違えもBookDetailRoute
を他の場所でも使うことができるおかげで少なくできます。
まとめ
go_routerを利用した画面遷移時のパラメーターの渡し方について、どういう渡し方があるのか、どういう場面で利用するべきなのかを整理できました。また、go_router_builderを利用することで安全にパラメーターを渡すことができ、開発時のミスを防ぐことが出来るようになりました。