GetXを廃止してGoRouterを使用してみた

こんにちは、株式会社Pentagonの小寺です。

これまで画面遷移や遷移時にデータを渡すためにGetXを使用していましたが、GetXを廃止してgo_routerを採用することにしたため、go_routerの使用方法や良さについてまとめていきたいと思います。

【こんな人に読んで欲しい】

go_routerを使用しようと考えている方
画面遷移時にデータを渡したい方

【この記事を読むメリット】

go_routerの使用方法がわかる
画面遷移時にデータの渡し方がわかる

目次

そもそもなぜGetXを廃止したのか

これまで使用していたGetXは遷移以外の機能も含まれており、不具合があった際に調査が困難であったため廃止しました。
なぜ新たにgo_routerを使用したかというと、遷移が簡単であり、公式(flutter.dev)によりメンテナンスされているためです。

使用するパッケージ

今回は画面遷移、遷移時に値を返すためにgo_routerを使用しました。
https://pub.dev/packages/go_router

ルーティングの設定

final GoRouter router = GoRouter(
    routes: <RouteBase>[
    GoRoute(
        path: '/',
        builder: (context, state) => const HomeScreen(),
      ),
    GoRoute(
        path: ‘/sign_up’,
        builder: (context, state) => const SettingScreen(),
      ),
    ],
);

routerの設定は上記のようにGoRouter()のroutes内にGoRoute()を設定しpathとbuilderを設定します。設定したrouterはMaterialApp.router内にセットします。

MaterialApp.router(
  routerConfig: router,
);

go_routerの遷移方法

遷移パターン go_routerの場合 Flutter標準の場合
渡す値がない場合かつ前の画面に戻る GoRouter.of(context).push(location名); GoRouter.of(context).pushNamed(path名); Navigator.of(context).push(); Navigator.of(context).pushNamed();
渡す値がない場合 かつ 前の画面に戻ることができない 新しい画面に遷移し、元の画面をスタックから削除する GoRouter.of(context).go(location名); GoRouter.of(context).goNamed(path名);
渡す値がない場合 かつ 前の画面に戻ることができない 新しい画面をルートにする GoRouter.of(context).pushReplacement(location名); GoRouter.of(context).pushReplacementNamed(path名); Navigator.of(context).pushReplacement(); Navigator.of(context).pushReplacementNamed();
渡す値がある場合  ※遷移方法については渡す値がない場合と同じため代表してpushのみ記載しております GoRouter.of(context).push(path名, extra: args); Navigator.of(context).pushNamed(path名, extra: args);
前のページに戻る GoRouter.of(context).pop(); Navigator.of(context).pop();

値を渡す方法

今回値を渡す方法については、sign_up_screenを使用して説明していこうと思います。
コードについてはgo_routerで値を渡す、受け取る箇所に絞ってコードを記載した上で流れを説明します。

sign_up_screen_arguments

class SignUpScreenArguments {
  const SignUpScreenArguments({
    this.signUpScreenMode = SignUpScreenMode.init,
    required this.email,
  });
  final SignUpScreenMode signUpScreenMode;
  final String email;
}

enum SignUpScreenMode {
  init,
  sendMail,
}

go_routerの設定

// サインアップ画面
      GoRoute(
        path: ‘/signUp’,
        builder: (context, state) =>
            SignUpScreen(state.extra as SignUpScreenArguments),
      ),

sign_up_screen

class SignUpScreen extends HookConsumerWidget {
  const SignUpScreen(this.args, {Key? key}) : super(key: key);
  final SignUpScreenArguments args;

  /// 初期表示レイアウト
  Widget getInit(BuildContext context, WidgetRef ref) {
    final notifier = ref.read(signUpScreenModelProvider.notifier);
    final emailController = notifier.emailController;
    final isSecure =
        ref.watch(signUpScreenModelProvider.select((value) => value.isSecure));
    final passwordController = notifier.passwordController;
    final passwordTextVerificationFailure = ref.watch(
      signUpScreenModelProvider
          .select((value) => value.passwordTextVerificationFailure),
    );
    return SizedBox(
            width: double.infinity,
            child: AcceptButton(
              label: '登録',
              textStyles: const [
                fontSize14,
                weight700,
                white,
              ],
              onPressed: () async {
                if (formKey.currentState?.validate() ?? false) {
                  OriginalProgress.show(context);
                  await notifier.signUp().then(
                    (value) {
                      OriginalProgress.dismiss(context);
                      GoRouter.of(context)
                        ..pop()
                        ..push(
                          AppRouter.signUp,
                          extra: SignUpScreenArguments(
                            signUpScreenMode: SignUpScreenMode.sendMail,
                            email: emailController.text,
                          ),
                        );
                    },
                    onError: (dynamic e) {
                      OriginalProgress.dismiss(context);
                      OriginalProgress.showError(
                        context,
                        e.toString(),
                      );
                    },
                  );
                }
              },
            ),
          ),
    );
  }

  /// メール送信レイアウト
  Widget getSendMailLayout(
    SignUpScreenArguments args,
  ) {
    return Text(
          args.email,
          style: textStyle(
            const [
              fontSize14,
              weight400,
            ],
          ),
    );
  }
}

sign_up_screenは前提としてSignUpScreenModeにあるinit(新規登録画面)とsendMail(メール送信画面)の2つのモードがあります。
GoRouterでの値の受け渡しはnull許容で渡すことができますがsign_up_screenには必ず値を渡したいのでnull許容せずに値を渡しています。
extraで渡された値はsign_up_screenで

final SignUpScreenArguments args;

として受け取られています。

sign_up_screen内にある登録ボタンを押下すると、下記の値を渡した遷移が行われます。
挙動としては登録時に入力したemailを受け渡してメール送信画面へとSignUpScreenModeを変更しています。

GoRouter.of(context)
  ..pop()
  ..push(
    AppRouter.signUp,
    extra: SignUpScreenArguments(
      signUpScreenMode: SignUpScreenMode.sendMail,
      email: emailController.text,
    ),
  );

実際の動き

まとめ

冒頭でも述べたように、go_routerはGetXとは違い遷移以外の機能がないため不具合があった際に調査がGetXに比べ容易である点、公式(flutter.dev)により定期的にメンテナンスされている点からgo_routerへの変更をしました。
値を渡す段階でエラーハンドリングすることができ、値を渡す際に予期しないエラーを未然に防ぐことができる点が使用していて便利と思った点です。

おまけ

Flutterに関する知識を深めたい方には、『Flutterの特徴・メリット・デメリットを徹底解説』という記事がおすすめです。

この記事では、Flutter アプリ開発の基本から、Flutter とは何か、そして実際のFlutter アプリ 事例を通じて、その将来性やメリット、デメリットまで詳しく解説しています。
Flutterを使ったアプリ開発に興味がある方、またはその潜在的な可能性を理解したい方にとって、必見の内容となっています。

ぜひ一度ご覧ください。

採用情報はこちら
目次