🦇

go_router_builder前のページに戻ると状態を更新したい 

2025/01/02に公開

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),
)

https://zenn.dev/joo_hashi/articles/98af31ba4e76bd

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);  // 型安全な戻り値
}

メリットのまとめ

  1. コンパイル時のエラー検出により、実行時エラーを防止
  2. 型安全な画面遷移で、パラメータの漏れや型の不一致を防止
  3. リファクタリング時の安全性向上
  4. コードの可読性と保守性の向上
  5. IDEのサポートによる開発効率の向上

go_router_builderを使用することで、より堅牢なアプリケーション開発が可能になります。特に大規模なアプリケーションや、複数人での開発時にそのメリットを実感できるでしょう。

Discussion