くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Flutterを再開するときにやったこと。その3(go_routerを使ってみる)

ルーティングライブラリをどうしようかと思ってたら、
go_routerがよさそうなので、試してみたときの備忘録。

Flutter Favoriteにもなっていて、
公式ドキュメントの日本語版もあるよう。

@_monoさんが作られているサンプルもあるのでよい感じ。

インストール

$ flutter pub add go_router
$ flutter pub get

使い方

ルーティングの定義

ルーティングの定義はこんな感じ。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import 'configs/const.dart';
import 'pages/home/home.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // #を使わないURLパスの形式に設定
  GoRouter.setUrlPathStrategy(UrlPathStrategy.path);
  runApp(const ProviderScope(child: App()));
}

// Routerの定義。Providerで取得できるようにしておく。
final routerProvider = Provider(
  (ref) => GoRouter(
    debugLogDiagnostics: true,
    routes: [
      GoRoute(
        path: "/",
        builder: (_, __) => const MyHomePage(title: "HOME"),
      )
    ],
  ),
);

class App extends ConsumerWidget {
  const App({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = ref.watch(routerProvider);
    // routerDelegateとrouteInformationParserに設定
    return MaterialApp.router(
      title: appName,
      theme: appTheme,
      routerDelegate: router.routerDelegate,
      routeInformationParser: router.routeInformationParser,
    );
  }
}

サンプルにあるとおり、
階層構造でルーティングを定義したり、
/users/:idみたいな動的なパスパラメタを受け取ることができる。

final routerProvider = Provider(
  (ref) => GoRouter(
    debugLogDiagnostics: true,
    routes: [
      GoRoute(
        path: '/',
        builder: (_, __) => const HomePage(),
        routes: [
          GoRoute(
            path: 'users',
            builder: (_, __) => const UsersPage(),
            routes: [
              GoRoute(
                path: ':id',
                builder: (_, state) => ProviderScope(
                  overrides: [
                    userIdProvider.overrideWithValue(state.params['id']!)
                  ],
                  child: const UserPage(),
                ),
              ),
            ],
          ),
        ],
      ),
    ],
  ),
);

Declarative Routing | go_router

画面遷移

定義したルートへの遷移は、BuildContextを使ってできる。

// navigate using the GoRouter more easily
onTap: () => context.go('/page2')

Linkウィジェットを使った方法でもOK。

Link(
  uri: Uri.parse('/page2'),
  builder: (context, followLink) => TextButton(
    onPressed: followLink,
    child: const Text('Go to page 2'),
  ),
),

まえのページへ戻るときは、pop()でOK。

context.pop();

Navigation | go_router

トップレベルのでリダイレクト(ログイン画面への遷移など)

ログインしてなかったらログイン画面に移動するなど、
全体のリダイレクトもできる。

class App extends StatelessWidget {
  final loginInfo = LoginInfo();
  ...
  late final _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => HomeScreen(families: Families.data),
      ),
      ...,
      GoRoute(
        path: '/login',
        builder: (context, state) => LoginScreen(),
      ),
    ],

    // redirect to the login page if the user is not logged in
    redirect: (state) {
      // if the user is not logged in, they need to login
      final loggedIn = loginInfo.loggedIn;
      final loggingIn = state.subloc == '/login';
      if (!loggedIn) return loggingIn ? null : '/login';

      // if the user is logged in but still on the login page, send them to
      // the home page
      if (loggingIn) return '/';

      // no need to redirect at all
      return null;
    },
  );
}

Redirection | go_router

以上!! これでだいぶ楽に(´ω`)

参考にしたサイトさま