⛩️

context.goとcontext.pushの違い?

2023/06/12に公開

使ってみて比較してみた

go_routerを半年使い続けてキャッチアップしてきたが、最近作ったコミュニティに入ってくれたSogaさんと議論するまで、ただ画面遷移することができる便利なパッケージとして使ってるだけで、画面遷移する時の状態については理解してなかったので、記事を書こうと思った。

コードの解説をする前に、設定とfullPathって何かの解説をします。

今回は、名前付きルートなるものを使ってないです。context.goNamedのことですね。
fullPathとは、String型で渡す値ですね。イメージしやすいように説明するとパスです。 '/'とか'/home'のことですね。

https://pub.dev/documentation/go_router/latest/go_router/GoRouterState/fullPath.html

path: の後にパスを書いたりますが、これだとボタンを押して画面遷移するコードを書くときに毎回パスを書かないといけません。なので、いつも名前付きルートを使ってたのですが、staticなfullPathを渡すクラスを作れば、コードを書きやすくなります。
enumを使う方法もあるのですが、あれは同じString型を渡すのですが、使いにくいとか、好みじゃないとか好き嫌いがあるみたいです😅

fullPathを渡すインスタンス化しないクラス
YouTubeで海外の人がやってるのを見て、以前知ったのですが、名前付きルートでやってたので、必要ないかなと思って使ってなかったです。
今回は、色々書き方のパターンがあるよってのを紹介したいので、書くことにしました。

root_path.dart
// Routesは、GoRouterで使用するパスを定義するクラスです。
class Routes {
  static const String home = '/';
  static const String item = '/item';
  static const String detail = '/detail';
}

go_routerの設定ファイル

router.dart
import 'package:design_patterns/domain/item_model.dart';
import 'package:design_patterns/presentation/router_path.dart';
import 'package:design_patterns/presentation/ui/detail.dart';
import 'package:design_patterns/presentation/ui/home.dart';
import 'package:design_patterns/presentation/ui/item_list.dart';
import 'package:design_patterns/presentation/ui/some_error.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

// goRouterProviderは、GoRouterを提供するProviderです。
final goRouterProvider = Provider<GoRouter>((ref) {
  return GoRouter(
    routes: [
      GoRoute(
        path: Routes.home, // pathは、GoRouterで使用するパスを定義します。
        builder: (context, state) {
          return const HomePage();
        },
      ),
      GoRoute(
        path: Routes.item,
        builder: (context, state) {
          return const ListItemPage();
        },
      ),
      // 次のページに遷移する際に、extraでItemクラスのnameプロパティを渡しています。
      GoRoute(
        path: Routes.detail,
        builder: (context, state) {
          final item = state.extra as Item?;
          // nullチェックを行います。
          if (item != null) {
            // extraで渡されたItemクラスのnameプロパティを表示するぺージに遷移します。
            return DetailPage(item: item);
          } else {
            // エラーが発生した場合は、SomeErrorPageに遷移します。
            return const SomeErrorPage(); // 適切なエラーページに差し替えてください
          }
        },
      ),
    ],
  );
});

context.pushの場合

画面遷移したページで、AppBarに戻るボタンが表示されます。これはページを重ねているから起きる現象です。スタックと表現するそうです。


context.goの場合

これは、よく使われる方法ですね。なんで戻るボタンが出てこないのか今までわかりませんでした?
戻るボタンを出すには、ルートをネストさせればできます。戻るボタンが出てこない原因は、現在のページをスタックから削除するからです。


画面遷移するページのコード

同じページに画面遷移するとどうなるか、比較するために2種類のボタンのコードを書いたページです。fullPathを渡すクラスを使っているので、 '/' とか書かなくてもコードの保管機能でパスを呼び出して、コードを書きやすくなっているので、使いやすくなっています。

// pathを直接書くパターン
context.go('/item');

// fullPathを渡すクラスを使ったパターン.
context.go(Routes.item);

画面遷移するコード

home.dart
import 'package:design_patterns/presentation/router_path.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                // pushは、現在のページをスタックに残したまま、新しいページをスタックに追加します。
                // ページ遷移のスタックとは、ページ遷移の履歴を保持するスタックのことです。
                context.push(Routes.item);
              },
              child: const Text('push'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                // goは、現在のページをスタックから削除して、新しいページをスタックに追加します。
                // 新しいページのスタックとは、ページ遷移の履歴を保持するスタックのことです。
                // AppBarに戻るボタンが表示されないのは、スタックから削除されたためです。
                context.go(Routes.item);
              },
              child: const Text('go'),
            ),
          ],
        ),
      ),
    );
  }
}

まとめ

今回作成したコードは他にも設定ファイルが複数あるので、記事には全部書きませんでした。ページの内容が増えすぎて見ると疲れてしまうと思うので、全体のコードを見たい方は、こちらのリンクから、Githubのソースコードを見てみてください。

https://github.com/sakurakotubaki/GoRouterFullPath

Discussion