🙆

flutter✖️GoRouter✖️Riverpod

2024/05/02に公開2

どうも!初心者プログラマーのちゃきです🙋‍♀️
goRouter✖️riverPodのシンプルなコードを書いて、理解を深めたいと思います!

はじめに~GoRouterとは~

公式によると、
「RouterAPIを使って、異なるスクリーン間をナビゲートするための便利なURLベースのAPIを提供するFlutter用の宣言型ルーティングパッケージ」だそうです!ページ間の関係を一括管理できるってことですね!
https://pub.dev/packages/go_router

予想図

Authページから、CloudStoreページとStorageページに移動できるようにします

①goRouterProviderを作る

go_routerパッケージをインストールして、以下のようにgoRouterのプロバイダーを作ります。
https://pub.dev/packages/go_router

import 'package:firebase_app/config/enum/router_enum.dart';
import 'package:firebase_app/features/auth/view/auth_page.dart';
import 'package:firebase_app/features/cloud_store/view/cloud_store_page.dart';
import 'package:firebase_app/features/storage/view/storage_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

final goRouterProvider = Provider<GoRouter>(
  (ref) {
    return GoRouter(
      initialLocation: AppRoute.auth.path, //初めに移動するページ
    

      routes: [
        GoRoute(
          path: AppRoute.auth.path,
          // トップレベルのパスが必要なので指定する.
          name: AppRoute.auth.name,
          builder: (BuildContext context, GoRouterState state) {
            return const AuthPage();
          },
          // ネストしたルートを指定する.
          routes: <RouteBase>[
            GoRoute(
              path: AppRoute.cloudStore.path,
              name: AppRoute.cloudStore.name,
              builder: (BuildContext context, GoRouterState state) {
                return const CloudStorePage();
              },
            ),
            GoRoute(
              path: AppRoute.storage.path,
              name: AppRoute.storage.name,
              builder: (BuildContext context, GoRouterState state) {
                return const StoragePage();
              },
            ),
          ],
        ),
      ],
    );
  },
);

②Enumでpath,nameを管理

ネストのページは、'/'が入っているとエラーになるので注意です!
'/'はトップのページにしかつかない!
Enumでpathとnameを一括管理します。
これで、打ち間違えのミスが減らせます☺️

enum AppRoute {
  auth,
  cloudStore,
  storage,
}

extension AppRouteExtention on AppRoute {
  String get path {
    switch (this) {
      case AppRoute.auth:
        return "/auth";
      case AppRoute.cloudStore:
        return "cloudStore";
      case AppRoute.storage:
        return "storage";

      default:
        return "/auth";
    }
  }
}

③main.dartで、goRouterをMyAppの中に設定する。

import 'package:firebase_app/routing/app_router.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  //MyAppをProviderScopeに指定し、全てのページでProviderを使えるようにする
  runApp(
    const ProviderScope(child: MyApp()),
  );
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // go_routerプロバイダーを監視する。
    final goRouter = ref.watch(goRouterProvider);
    return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      // MaterialAppにrouterを追加。
      routerConfig: goRouter, //goRouterを基盤に設定する。
      title: 'riverpod ✖️ go_router',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}

これでgoRouterの設定が完了しました!
あとはそれぞれのページでページ移動コードを呼ぶだけです。

④画面内で移動用コードを書く

import 'package:firebase_app/config/enum/router_enum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Authページ'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            //Authページへ移動
            const Text('cloudStoreページへ'),
            ElevatedButton(
              onPressed: () {
                context.goNamed(AppRoute.cloudStore.name);
              },
              child: const Text('移動する'),
            ),
            const SizedBox(height: 50),

            //Storageページへ移動
            const Text('storageページへ'),
            ElevatedButton(
              onPressed: () {
                context.goNamed(AppRoute.storage.name);
              },
              child: const Text('移動する'),
            ),
          ],
        ),
      ),
    );
  }
}

おわりに

ここまで読んでくださりありがとうございます✨✨
次は、riverpod✖️goRouter✖️bottomnavigationの実装の記事を書こうと思うので、また見に来てください😁

Discussion

osakiosaki

②Enumでpath,nameを管理

extensionを使わずとも、enhanced enumで良さそうですね。
参考:Declaring enhanced enums

enum AppRoute {
  auth('/auth'),
  cloudStore('cloud-store'),
  storage('storage');
  
  final String path;
  
  const AppRoute(this.path);
}

そうすれば、AppRoute.auth.pathのようにアクセスでき、switchのdefaultのような"それ以外"が入り込む余地がありません。

余談ですが、パスにはkebab case(ケバブケース、ハイフンのやつ)を使った方が良いかもですね。(cloudStoreではなくcloud-store)
参考:URL structure best practices for Google

ちゃきりこちゃきりこ

osakiさん コメントありがとうございます✨
enhanced enumsというものがあるのですね!こちらの方がコードもシンプルで使いやすそうです!
勉強になります🙏早速使ってみます!