🦇
go_router_builder前のページに戻ると状態を更新したい
goではなくpushを使う
前回はNavigator.of(context).push<bool>を使用して、Formからデータを保存した後に、前のページに戻り値を返して状態を更新する方法をやってみました。
こちらですね。
FloatingActionButton(
onPressed: () async {
final result = await Navigator.of(context).push<bool>(
MaterialPageRoute(builder: (context) => const CreateTodoPage()),
);
if (result == true && context.mounted) {
setState(() {}); // 保存成功時に更新
}
},
child: const Icon(Icons.add),
)
go_router_builderだとどうすればいいのか?
READMEによると.push<bool>
を使うそうだ。go<bool>
とは書けない。
公式の解説を翻訳すると以下のように書いてあった。
戻り値
go_router 6.5.0から、ルートをプッシュし、その後にそれをポップすると、戻り値を生成できるようになりました。生成されるルートもこの機能に従います。
final bool? result =
await const FamilyRoute(fid: 'John').push<bool>(context);
遷移するときのコード
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await const CreateTodoRoute().push<bool>(context);
if (result == true && mounted) {
setState(() {}); // 保存成功時に更新
}
},
child: const Icon(Icons.add, color: Colors.black),
),
popするコード
context.pop()で戻ることはできる。
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
await TodoRepository.instance.createTodo(
title: _titleController.text,
content: _contentController.text,
);
if (context.mounted) {
context.pop(true); // 保存成功を示すtrueを返す
}
}
},
child: const Text('Create'),
),
使い分け
- 結果を受け取る必要がある場合(フォーム入力など): pushを使用
- 単純な画面遷移の場合(詳細画面表示など): goを使用
今回のケースでは、CreateTodoPageから保存成功/失敗の結果を受け取る必要があるため、pushを使用する必要があります。
go_router_builderは使いこなすのが難しい💦
最近のFlutter案件では、go_router_builderを使いたがる人が多い。普通のgo_routerを覚えたら学習したほうが良さそうだ。
最後にgo_router_builderについて調べたことを書いておきます。
go_router_builderのメリット:型安全なルーティングの実現
go_router_builderを使用することで、Flutter開発における多くの利点が得られます。主なメリットを実装例と共に紹介します。
1. コンパイル時の型チェック
型安全なルーティングにより、実行時エラーを防ぎます:
// ✅ 正しい使用例
final result = await const CreateTodoRoute().push<bool>(context);
// ❌ コンパイルエラー例:必須パラメータの欠落
class TodoDetailRoute extends GoRouteData {
const TodoDetailRoute({required this.todoId}); // todoIdが必須
final int todoId;
Widget build(BuildContext context, GoRouterState state) => TodoDetailPage(todoId: todoId);
}
// コンパイルエラー:todoIdが指定されていない
const TodoDetailRoute().go(context);
2. 宣言的なルート定義
アノテーションを使用した明確なルート定義が可能です:
<CreateTodoRoute>(
path: '/todo/create',
)
class CreateTodoRoute extends GoRouteData {
const CreateTodoRoute();
Widget build(BuildContext context, GoRouterState state) => const CreateTodoPage();
}
3. 戻り値の型安全性
画面遷移の戻り値も型安全に扱えます:
// CreateTodoPageからbool型の結果を受け取る
final bool? result = await const CreateTodoRoute().push<bool>(context);
if (result == true) {
// 保存成功時の処理
}
4. IDEサポートの恩恵
- 入力補完による正確なルート名の提案
- パラメータの型情報がリアルタイムで表示
- リファクタリング時の自動更新
5. 実装例
実際のアプリケーションでの使用例:
// ルート定義
<TodoListRoute>(
path: '/todo',
routes: [
TypedGoRoute<CreateTodoRoute>(path: 'create'),
TypedGoRoute<TodoDetailRoute>(path: 'detail/:todoId'),
],
)
// 画面遷移
final result = await const CreateTodoRoute().push<bool>(context);
// 結果の返却(CreateTodoPage内)
if (saved) {
context.pop(true); // 型安全な戻り値
}
メリットのまとめ
- コンパイル時のエラー検出により、実行時エラーを防止
- 型安全な画面遷移で、パラメータの漏れや型の不一致を防止
- リファクタリング時の安全性向上
- コードの可読性と保守性の向上
- IDEのサポートによる開発効率の向上
go_router_builderを使用することで、より堅牢なアプリケーション開発が可能になります。特に大規模なアプリケーションや、複数人での開発時にそのメリットを実感できるでしょう。
Discussion