79078093

Date: 2024-10-11 11:54:10
Score: 0.5
Natty:
Report link

If you are using an authState provider to check if user is logged in or not and redirect him, using go_router is quite tricky. When I started using the redirect method of GoRouter it seems really easy to manage, but then I realized that the hot reload always redirected me to the initialRoute '/'. In my project I use riverpod to check for the authState (ref.watch(currentUserAccountProvider)). But to use this code in the GoRouter config, the config must be dynamic (vs static). And it result of re-initializing GoRouter config each time your app is rebuilt (-> redirect to "/")

So here is my solution. I am quite new to Flutter so I don't know if it's a good practice or not, experienced users could say, but at least it works for me.

GoRouter config file :

/// The route configuration.
class MyRouterConfig {
  MyRouterConfig();

  GoRouter get router => _router;

  static final GoRouter _router = GoRouter(
    routes: <RouteBase>[
      GoRoute(
        path: '/signin',
        builder: (BuildContext context, GoRouterState state) {
          return const SignInView();
        },
      ),
      GoRoute(
        path: '/signup',
        builder: (BuildContext context, GoRouterState state) {
          return const SignUpView();
        },
      ),
      GoRoute(
        path: '/',
        builder: (BuildContext context, GoRouterState state) {
          return const HomeView();
        },
      ),
      GoRoute(
        path: '/otherview',
        builder: (BuildContext context, GoRouterState state) {
          return const OtherView();
        },
      ),
    ],
    routerNeglect: true,
  );
}

Then I created a widget to manage the redirection following the authState: CheckAuthWidget :

class CheckAuthWidget extends ConsumerWidget {
  final Widget child;
  const CheckAuthWidget({super.key, required this.child});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final currentUserAccount = ref.watch(currentUserAccountProvider);
    final GoRouter router = MyRouterConfig().router; // Get the router config directly from MyRouterConfig instead of GoRouter.of(context)
    final currentLocation = router.routerDelegate.currentConfiguration.fullPath;
    final List<String> authorizedRoutes = ['/signin', '/signup'];

    currentUserAccount.when(
      data: (user) {
        // If the user is not connected -> redirect to /signin
        if (user == null && !authorizedRoutes.contains(currentLocation)) {
          router.go('/signin');
        }

        if (user != null &&
            (currentLocation == '/signin' || currentLocation == '/signup')) {
          router.go('/');
        }
      },
      loading: () {},
      error: (error, stackTrace) {},
    );

    return child;
  }
}

Here is my main :

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(const ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return MaterialApp.router(
        title: 'Family Menu',
        routerDelegate: MyRouterConfig().router.routerDelegate,
        routeInformationParser:
            MyRouterConfig().router.routeInformationParser,
        routeInformationProvider:
            MyRouterConfig().router.routeInformationProvider,
        scaffoldMessengerKey: scaffoldMessengerKey,
        supportedLocales: AppLocalizations.supportedLocales,
        localizationsDelegates: AppLocalizations.localizationsDelegates,
        debugShowCheckedModeBanner: false,
        builder: (context, child) => CheckAuthWidget(child: child!),
    );
  }
}

I hope this could help someone else, and please tell me if I am doing something wrong :)

Reasons:
  • Whitelisted phrase (-1): works for me
  • RegEx Blacklisted phrase (2.5): please tell me
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: eInyzant