9

I was using go_router in a project. I had a separate file with an instance of GoRouter with all the routes (home, login, register). Then, I added authentication with a cubit. So I had to modify my GoRouter instance to a function that received with auth cubit and use it to redirect to the appropriate route.

Everything seemed alright but then I realized something. For example, if I was in the login route and push register to the stack and modify the register page and save the file, the hot reload would take me back to login. So every time I want to make some changes to the register page, I would go back to the login route and then manually go back to the register to see my changes.

Here is an example:

Demo app

PS: I just started using the go_router package so maybe I am doing something incorrectly.

Miguel Yurivilca
  • 375
  • 5
  • 12

6 Answers6

8

The solution is simple


GoRouter store state of your routes. If you create new instance of GoRouter then it lose state and navigate you to initial route.

To solve this problem I create Instance of GoRouter and store it as Singleton or as Global instance.

class AuthNavigation {

  static const String settings = '/';
  static const String myFriends = '/my_friends';
  
  
  final GoRouter goRouter; // This instance will be store route state
  
  AuthNavigation() : goRouter = _router;

  static GoRouter get _router => GoRouter(
        routes: <GoRoute>[...],
      );
      
}
  • I understand why everyone is saying to make the GoRouter object a final variable or to make it a singleton, but how would that work with a refresh listenable that is being provided by riverpod? – Wheathin May 25 '23 at 19:15
1

Simply mark your router as static, so that it uses the same instance when you initialize it everytime in MaterialApp.router()

class AppRouter {
  static final GoRouter _router = GoRouter(
    routes: [
      GoRoute(
        path: "/",
        builder: (context, state) => const HomeScreen(),
      ),
    ],
  );

  GoRouter get router => _router;
}

And, In MaterialApp.router():

MaterialApp.router(
   routerDelegate: AppRouter().router.routerDelegate,
   routeInformationProvider: AppRouter().router.routeInformationProvider,
   routeInformationParser: AppRouter().router.routeInformationParser,
 )
Dinesh Bala
  • 947
  • 7
  • 8
1

I've made a workaround that works ok. You can check out the template repo with example code.

It consists of Splash, OnBoarding, SignIn, and Home with NavBar and child pages.

There is also use of redirect together with an AuthState ChangeNotifier.

https://github.com/Christer-Muntean/go_router_with_navbar

You can check out the app video preview here: https://www.utvikler.app/post/spar-tid-og-ressurser-effektiv-navigering-i-flutter-med-go_router-utforsk-v%C3%A5rt-github-repo

Christer
  • 2,746
  • 3
  • 31
  • 50
0

Try to implement like this:

class MyApp extends ConsumerWidget {
  MyApp({Key? key}) : super(key: key);
  late final appRoutes = AppRoutes();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final ThemeModeState currentTheme = ref.watch(themeProvider);

    return MaterialApp.router(
      title: 'Starmie',
      debugShowCheckedModeBanner: false,
      theme: lightTheme,
      darkTheme: darkTheme,
      themeMode: currentTheme.themeMode,
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      routeInformationParser: appRoutes.goRouter.routeInformationParser,
      routerDelegate: appRoutes.goRouter.routerDelegate,
      routeInformationProvider: appRoutes.goRouter.routeInformationProvider,
    );
  }
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Locxeu
  • 1
  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Jan 14 '23 at 10:27
0

By following code you can achieve desire output.

///this class contaqins list of go router which will be use in the app
class AppRoute {
  // using a factory is important
  // because it promises to return _an_ object of this type
  // but it doesn't promise to make a new one.
  ///return the instance of the
  factory AppRoute() => _instance;
  AppRoute._internal() {
    // initialization logic
  }
  // This named constructor is the "real" constructor
  // It'll be called exactly once, by the static property assignment above
  // it's also private, so it can only be called in this class

  static final AppRoute _instance = AppRoute._internal();
  static final GoRouter _router = GoRouter(
    navigatorKey: _rootNavigatorKey,
    routes: routeBase,
    errorBuilder: (BuildContext context, GoRouterState state) =>
        const NotFound(),
  );

  ///list of route base for the router
  static List<RouteBase> routeBase = <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) =>
          const SpalshScreen(),
    ),
    GoRoute(
        path: AppRoutes.internalError,
        builder: (BuildContext context, GoRouterState state) =>
            const InternalError()),

  ];

  ///retrun router object with initial location
  static GoRouter getRoute(String initialLocation) => GoRouter(
        navigatorKey: _rootNavigatorKey,
        routes: routeBase,
        initialLocation: initialLocation,
        errorBuilder: (BuildContext context, GoRouterState state) =>
            const NotFound(),
      );

  ///return router object
  static GoRouter get router => _router;
}

///this class hold the custom routes name that will be use in the app
class AppRoutes {
  ///return routename ='internal-error'
  static String internalError = '/internal-error';

}
0

You should define the route class you created as final and give it to Material App. It worked for me. final _appRouter = NavigatorRoutes(); routerConfig: _appRouter.router,

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  await EasyLocalization.ensureInitialized();
  runApp(EasyLocalization(
    supportedLocales: LocalizationsConfig.supportedLocales,
    path: LocalizationsConfig.path,
    child: App(),
  ));
}

class App extends StatelessWidget {
  App({super.key});
  final _appRouter = NavigatorRoutes();
  final _providers = Providers();
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: _providers.items,
      child: MaterialApp.router(
        debugShowCheckedModeBanner: false,
        title: 'Map Mates',
        theme: AppTheme.baseScheme,
        routerConfig: _appRouter.router,
      ),
    );
  }
}

My NavigatorRoutes class is like this

part of 'app_config.dart';

class NavigatorRoutes {
  final GoRouter router = GoRouter(
    errorBuilder: (BuildContext context, GoRouterState state) => const NotFoundPage(),
    initialLocation: RouteName.root.path,
    routes: <RouteBase>[
      GoRoute(
        path: RouteName.root.path,
        builder: (BuildContext context, GoRouterState state) {
          return const Root();
        },
        routes: <RouteBase>[
          GoRoute(
            path: RouteName.mapScreen.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const MapBasePage();
            },
          ),
          GoRoute(
            path: RouteName.loginScreen.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const LoginPage();
            },
          ),
          GoRoute(
            path: RouteName.singInScreen.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const SingInPage();
            },
          ),
          GoRoute(
            path: RouteName.frogPassPage.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const FrogPassPage();
            },
          ),
          GoRoute(
            path: RouteName.homePage.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const HomePage();
            },
          ),
          GoRoute(
            path: RouteName.editProfilePage.routeName,
            builder: (BuildContext context, GoRouterState state) {
              return const EditProfilePage();
            },
          ),
        ],
      ),
      GoRoute(
        path: RouteName.camera.path,
        builder: (BuildContext context, GoRouterState state) {
          return const CameraPage();
        },
      ),
      GoRoute(
        path: RouteName.playerPage.path,
        builder: (BuildContext context, GoRouterState state) {
          var data = state.extra as Map<String, dynamic>;
          return EditContentPage(
            imageFile: data['imageFile'],
            videoFile: data["videoFile"],
          );
        },
      ),
    ],
  );
}
Hasan koç
  • 51
  • 3