go_router + Riverpod2.0で画面遷移をする
パッケージ独特のエラーにハマった!
最近画面遷移は、go_routerを使うことが増えてきたのですが、設定が原因なのか、パッケージ独特のエラーに悩まされました。
最近、go_toureの記事を色々書きましたが、設定が人によって違うのか真似するだけだと変なエラーに悩まされます😇
今回はpub.devを参考にルートの設定をしたデモアプリを作りました。
遭遇したエラー
'package:go_router/src/configuration.dart': Failed assertion: line 37 pos 18: 'route.path.startsWith('/')': top-level path must
'package:go_router/src/configuration.dart': Failed assertion: line 37 pos 18: 'route.path.startsWith('/')': トップレベルのパスが必要です。
解決方法
パスに / をつけてトップレベルのルートを指定する。これができていないとパッケージ独特のエラーが発生する。他にも原因不明のエラーが多かったので、海外の人のコードを参考に作ったのが原因だと思い、ゲッターをなくして、コンストラクターをつけて、名前付きルートの作成に使用しました。
まずは表示する画面を作成
lib配下にapplicationディレクトリを作成してuiディレクトリを作成しファイルを追加していきます。
最初に表示される画面
ここから、画面遷移をして他のページへ移動する。ネストしているルートと、していないルートだと、戻るボタンが表示されなかったり、context.popが使用できないのがわかった😁
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:go_routet_redirect/application/ui/next_page.dart';
import 'package:go_routet_redirect/go_router_riverpod/home_page.dart';
class StartScreen extends ConsumerWidget {
const StartScreen({super.key});
static const rootName = '/'; // 名前付きルートで使うコンストラクターを定義しておく.
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text("Start Screen")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Wellcome"),
ElevatedButton(
onPressed: () {
// 名前付きルートで画面遷移するコード.
// ネストしたルートに画面遷移する.
context.goNamed(NextPage.rootName);
},
child: const Text("NextPage"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 名前付きルートで画面遷移するコード.
// 通常の画面遷移をするコード.
context.goNamed(HomePage.rootName);
},
child: const Text("HomePage"),
),
],
),
),
);
}
}
ネストしたルート
こちらのページでは、AppBarに戻るボタンが表示されて、context.popを使用することができる。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
class NextPage extends ConsumerWidget {
const NextPage({super.key});
static const rootName = 'nextPage';
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text("NextPage")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Welcome to NextPage"),
ElevatedButton(
onPressed: () {
// 前のページへ戻るコード
context.pop();
},
child: const Text("Back"),
),
],
),
),
);
}
}
ネストしていないルート
こちらのページでは、AppBarに戻るボタンが表示されず、context.popを使用することができない。使うとエラーが発生する😱
前のページに戻りたいときは、context.go, context.goNamedを使用する。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:go_routet_redirect/application/ui/next_page.dart';
import 'package:go_routet_redirect/go_router_riverpod/home_page.dart';
class StartScreen extends ConsumerWidget {
const StartScreen({super.key});
static const rootName = '/'; // 名前付きルートで使うコンストラクターを定義しておく.
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text("Start Screen")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Wellcome"),
ElevatedButton(
onPressed: () {
// 名前付きルートで画面遷移するコード.
// ネストしたルートに画面遷移する.
context.goNamed(NextPage.rootName);
},
child: const Text("NextPage"),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 名前付きルートで画面遷移するコード.
// 通常の画面遷移をするコード.
context.goNamed(HomePage.rootName);
},
child: const Text("HomePage"),
),
],
),
),
);
}
}
ルートの設定ファイル
Riverpodを使用しているので、go_toureをプロバイダーでラップして、どこからでもアクセスできるように設定します。
参考になったサイト
ルートの設定ファイル
applicationディレクトリにルートの設定ファイルを作成します。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:go_routet_redirect/application/ui/home_page.dart';
import 'package:go_routet_redirect/application/ui/next_page.dart';
import 'package:go_routet_redirect/application/ui/start_screen.dart';
final goRouterProvider = Provider<GoRouter>((ref) {
return GoRouter(
routes: <RouteBase>[
// 最初に表示されるページ.
GoRoute(
path: '/', // トップレベルのパスが必要なので指定する.
name: StartScreen.rootName, // 名前付きルートを指定する.
builder: (BuildContext context, GoRouterState state) {
return const StartScreen();
},
// ネストしたルートを指定する.
routes: <RouteBase>[
GoRoute(
path: 'next',
name: NextPage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const NextPage();
},
),
],
),
// ネストしていないルート。戻るボタンがAppBarに表示されない.
GoRoute(
path: '/home',
name: HomePage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
),
],
);
});
main.dartでgo_routerを使えるように設定をする
Firebaseのコードが書いてありますが、こちらは気にしないでください。認証機能の実験で使っていたので、書きました。一旦コメントアウトしてます。
リダイレクトの実験をしていたのですが、上手くいかなくて悩まされております😭
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'application/router.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
Widget build(BuildContext context, WidgetRef ref) {
// go_routerをプロバイダーで監視する.
final goRouter = ref.watch(goRouterProvider);
return MaterialApp.router(// MaterialAppに.routerを追加する.
routerConfig: goRouter,// このコードを追加すると画面遷移ができるようになる.
title: 'flutter_riverpod + go_router Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
まとめ
go_routerを使い始めて、パッケージ独特のエラーにハマるので、今回は簡単な画面遷移をRiverpodで使う方法を記事にしてみました。
新たにページを追加したのですが、またエラーが出てきました😅
'package:go_router/src/configuration.dart': Failed assertion: line 37 pos 18: 'route.path.startsWith('/')': top-level path must
'package:go_router/src/configuration.dart': Failed assertion: line 37 pos 18: 'route.path.startsWith('/')': トップレベルのパスが必要です。
ネストしていないところは、トップレベルになるそうで / をつける。この後エラーが表示されなくなりました。
トップレベルのページを追加したコード
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:go_routet_redirect/auth/auth.dart';
import 'package:go_routet_redirect/auth/ui/home_page.dart';
import 'package:go_routet_redirect/auth/ui/next_page.dart';
import 'package:go_routet_redirect/auth/ui/signin_page.dart';
import 'package:go_routet_redirect/auth/ui/signup_page.dart';
import 'package:go_routet_redirect/auth/ui/start_screen.dart';
final goRouterProvider = Provider<GoRouter>((ref) {
final authState = ref.watch(authProvider);
return GoRouter(
initialLocation: '/',
routes: <RouteBase>[
// 最初に表示されるページ.
GoRoute(
path: '/', // トップレベルのパスが必要なので指定する.
name: StartScreen.rootName, // 名前付きルートを指定する.
builder: (BuildContext context, GoRouterState state) {
return const StartScreen();
},
// ネストしたルートを指定する.
routes: <RouteBase>[
GoRoute(
path: 'next',
name: NextPage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const NextPage();
},
),
],
),
// ネストしていないルート。戻るボタンがAppBarに表示されない.
// トップレベルのルートになるので、 / をつける
GoRoute(
path: '/home',
name: HomePage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
),
GoRoute(
path: '/signin',
name: SignInPage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
),
GoRoute(
path: '/signup',
name: SignUpPage.rootName,
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
),
],
);
});
Discussion