context.goとcontext.pushの違い?
使ってみて比較してみた
go_routerを半年使い続けてキャッチアップしてきたが、最近作ったコミュニティに入ってくれたSogaさんと議論するまで、ただ画面遷移することができる便利なパッケージとして使ってるだけで、画面遷移する時の状態については理解してなかったので、記事を書こうと思った。
コードの解説をする前に、設定とfullPathって何かの解説をします。
今回は、名前付きルートなるものを使ってないです。context.goNamedのことですね。
fullPathとは、String型で渡す値ですね。イメージしやすいように説明するとパスです。 '/'とか'/home'のことですね。
path: の後にパスを書いたりますが、これだとボタンを押して画面遷移するコードを書くときに毎回パスを書かないといけません。なので、いつも名前付きルートを使ってたのですが、staticなfullPathを渡すクラスを作れば、コードを書きやすくなります。
enumを使う方法もあるのですが、あれは同じString型を渡すのですが、使いにくいとか、好みじゃないとか好き嫌いがあるみたいです😅
fullPathを渡すインスタンス化しないクラス
YouTubeで海外の人がやってるのを見て、以前知ったのですが、名前付きルートでやってたので、必要ないかなと思って使ってなかったです。
今回は、色々書き方のパターンがあるよってのを紹介したいので、書くことにしました。
// Routesは、GoRouterで使用するパスを定義するクラスです。
class Routes {
static const String home = '/';
static const String item = '/item';
static const String detail = '/detail';
}
go_routerの設定ファイル
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);
画面遷移するコード
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のソースコードを見てみてください。
Discussion