🐽
画面遷移のボタンをコンポーネント化したい
どこまでできる?
画面遷移のコードを短くかける方法を試したことはあるけど、ロジックだけではなくボタンまで、使い回せるようにする方法は試したことがなかった!
以前こんな記事を書いたことがあります🧑💻
でも、go_routerを使うのが最近はマストになってきたので、コンポーネント化したボタンでもgo_routerで画面遷移できるか実験してみました。
画面遷移のボタンをコンポーネント化する
画面遷移に使うボタンのWidgetを切り分けてコンポーネント化してみた。やることは、
ボタンの名前と画面遷移するWidgetクラスを引数として渡すだけ。
何故コンポーネントするのか?
- 長いコードを書かずにすむ.
- 画面遷移するだけなら使いませる
このようなコンポーネントを作る
class _PushButton extends StatelessWidget {
const _PushButton({
super.key,
required this.buttonTitle,
required this.pageName,
});
final String buttonTitle; // ボタンのタイトルを引数として渡す
final Widget pageName; // 画面遷移先のWidgetクラスを引数として渡す
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => pageName));
},
child: Text(buttonTitle));
}
}
使用例
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
PushButton(buttonTitle: 'Next Page', pageName: NextPage()),
SizedBox(height: 20),
PushButton(buttonTitle: 'MyPage', pageName: MyPage()),
],
),
),
);
}
}
コンポーネント化したボタンを呼び出すだけで、書くコードの量を減らせましたね。次はgo_routerを使ってみましょう。
パッケージを追加する
flutter pub add go_router
コードを修正して使ってみる
修正といってもルートのパスをString型の文字として、コンストラクター(初期値)として使えるようにしたぐらいですね。画面遷移のコードは、go_routerに変更してあります。
名前付きルートと呼ばれているものあるのですが、公式によると非推奨なので使うべきかと思い、今回はパスを指定する方法にしました。
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class PushButton extends StatelessWidget {
const PushButton({
super.key,
required this.buttonTitle,
required this.rootPath,
});
final String buttonTitle; // ボタンのタイトルを引数として渡す
// final Widget pageName; // 画面遷移先のWidgetクラスを引数として渡す
final String rootPath; // パスを文字として渡す
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
// Navigator.of(context)
// .push(MaterialPageRoute(builder: (context) => pageName));
GoRouter.of(context).go(rootPath);
},
child: Text(buttonTitle));
}
}
ルートを定義する
go_routerの画面遷移の設定を定義する。全てトップレベルのパスなので、文字の先頭に / をつける。
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:navigator_widget/main.dart';
import 'package:navigator_widget/ui/mypage.dart';
import 'package:navigator_widget/ui/next_page.dart';
/// The route configuration.
final GoRouter goRouter = GoRouter(
routes: <RouteBase>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return const MyHomePage();
},
),
GoRoute(
path: '/next',
builder: (BuildContext context, GoRouterState state) {
return const NextPage();
},
),
GoRoute(
path: '/my_page',
builder: (BuildContext context, GoRouterState state) {
return const MyPage();
},
),
],
);
使うときは、こんな風にボタンの名前とルートのパスを引数に渡してあげるだけです。
import 'package:flutter/material.dart';
import 'package:navigator_widget/components/push_button.dart';
import 'package:navigator_widget/root.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: goRouter,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MyHome Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
// PushButton(buttonTitle: 'Next Page', pageName: NextPage()),
// SizedBox(height: 20),
// PushButton(buttonTitle: 'MyPage', pageName: MyPage()),
PushButton(buttonTitle: 'Go Next', rootPath: '/next'),
SizedBox(height: 20),
PushButton(buttonTitle: 'Go MyPage', rootPath: '/my_page'),
],
),
),
);
}
}
画面遷移先のコード
戻るボタンがついているだけ。。。
import 'package:flutter/material.dart';
import 'package:navigator_widget/components/push_button.dart';
class NextPage extends StatelessWidget {
const NextPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Next Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
PushButton(buttonTitle: 'Back', rootPath: '/'),
],
)),
);
}
}
import 'package:flutter/material.dart';
import 'package:navigator_widget/components/push_button.dart';
class MyPage extends StatelessWidget {
const MyPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MyPage'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
PushButton(buttonTitle: 'Back', rootPath: '/'),
],
)),
);
}
}
まとめ
なぜか、ネストしたルートでパスを定義すると、ビルドするときにエラーが発生してしまいました!
もしかしたら、無理してWidgetをコンポーネント化するのは良くないのかもしれないです🤔
こちらが完成品のソースコードです。何かお役立つと良いですが。。。
Discussion