go_router and flutter_bloc: Unhandled Exception: No GoRouter found in context
Asked Answered
P

3

15

I have wrapped the MaterialApp with a BlocProvider / BlocListener

I get an error

"Unhandled Exception: 'package:go_router/src/router.dart': Failed assertion: line 280 pos 12: 'inherited != null': No GoRouter found in context" from the Listener callback
Widget build(BuildContext context) {
    return BlocProvider<AuthenticationBloc>(
      create: (context) => AuthenticationBloc()..add(AppStarted()),
      child: BlocListener<AuthenticationBloc, AuthenticationState>(
        listener: (context, state) {
          if (state is AuthenticationUnauthenticated) {
            context.goNamed(LoginPage.routeName);
          }
          if (state is AuthenticationAuthenticated) {
            context.goNamed(NavigationBarContainer.routeName);
          }
        },
        child: MaterialApp.router(
            title: 'Flutter Demo',
            routeInformationProvider: _router.routeInformationProvider,
            routeInformationParser: _router.routeInformationParser,
            routerDelegate: _router.routerDelegate,
            theme: ThemeData(
              primarySwatch: Colors.blue,
            )),
      ),
    );
  }
Pridgen answered 5/11, 2022 at 11:8 Comment(2)
This looks like what we want but it seems to have been taken away from the latest version. Checking the change logs it says to use MaterialApp.builder, which I have done, but I still have the same error.Indeterminism
Just use router.go('/route_name') instead of context.go('route_name')Ratchet
I
11

You are attempting to navigate with context from higher up in the widget tree than go_router gets inserted.

I don't know where your GoRouter() routerConfig is, and where it is called from when you use a RouterDelegate, (maybe you don't need to use a delegate?) but you need to call your GoRouter configuration directly, and navigate from that.

So you need to change:

context.goNamed(LoginPage.routeName)

to

routerConfig.goNamed(LoginPage.routeName)

For me, you can see I pass the routerConfig to MaterialApp.router, and I also navigate directly from that, with routerConfig.go(HOME), from above the MaterialApp:

    ref.watch(authStatusServiceProvider).whenData((authStatus) {
      switch (authStatus) {
        case AuthenticationStatusEnum.authenticated:
          routerConfig.go(HOME);
          break;
        case AuthenticationStatusEnum.unauthenticated:
          routerConfig.go(LOGGED_OUT_HOME);
          break;
        default:
          routerConfig.go(LOGGED_OUT_HOME);
          break;
      }
    });

    return MaterialApp.router(
      theme: lightTheme,
      debugShowCheckedModeBanner: false,
      darkTheme: darkTheme,
      routerConfig: routerConfig,
    );
  }

All credit goes to darshankawar on Github.

Indeterminism answered 2/1, 2023 at 21:44 Comment(3)
Unfortunately, this answer iis not related to the question's contextConciliar
@KrishnaAcharya It is the same issue as in the question. Trying to navigate with go_router from the context, higher up in the widget tree than the go_router gets inserted.Indeterminism
Sorry I may be unaware of this , but the answer doesn't seem promising to me.Conciliar
T
4

You can navigate to other screen by go_router without context by GoRouter config object:

class AppRouter{
static GoRouter router = GoRouter(routes: GoRoute(name: otherScreenName, path: otherScreenPath, builder: (context, state)=> const OtherScreen()));
}

And from any where you want to navigate to OtherScreen call:

AppRouter.router.go(otherScreenPath);
Tonometer answered 10/10, 2023 at 2:19 Comment(0)
C
-2

This is happening because you are using context of go_router before it is initialized !!

Widget build(BuildContext context) {
    return BlocProvider<AuthenticationBloc>(
      create: (context) => AuthenticationBloc()..add(AppStarted()),
      child: BlocListener<AuthenticationBloc, AuthenticationState>(
        listener: (context, state) {
          if (state is AuthenticationUnauthenticated) {
            context.goNamed(LoginPage.routeName);              // 👈 Go router is not initilaized yet
          }
          if (state is AuthenticationAuthenticated) {
            context.goNamed(NavigationBarContainer.routeName); // 👈 Go router is not initilaized yet
          }
        },
        child: MaterialApp.router(
            routeInformationProvider: _router.routeInformationProvider,
            routeInformationParser: _router.routeInformationParser,
            routerDelegate: _router.routerDelegate,            // 👈 Your router is initialized here
      ),
    );
  }

Make changes to :

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
        providers: [
          BlocProvider<AuthenticationBloc>(
            create: (context) => AuthenticationBloc()..add(AppStarted()), 👈 Specify only the BlocProvider here
          ),
        ],
        child: MaterialApp(
            theme: customTheme(context),
            debugShowCheckedModeBanner: false,
            routeInformationProvider: _router.routeInformationProvider,
            routeInformationParser: _router.routeInformationParser,
            routerConfig: router,
  }

And then try to navigate inside the routerlike:

final GoRouter router = GoRouter(routes: [
  GoRoute(
      path: "/",
      builder: (context, state) {
        return BlocBuilder<AuthCubit, AuthState>(
          buildWhen: (oldState, newState) {
            return oldState is AuthInitialState;
           },
          builder: (context, state) {
            if (state is AuthenticationUnauthenticated) {
              // return const LoginPage();                         // alternative way
               context.goNamed(LoginPage.routeName);               👈 Use conditional routing using context here 
            } else if (state is NavigationBarContainer.routeName) {
              // return SignIn();                                 // alternative way
                context.goNamed(NavigationBarContainer.routeName); 👈 Use conditional routing using context here 
            } else {
              return const Scaffold();
            }
          },
        );
      }),
Conciliar answered 3/1, 2023 at 2:22 Comment(3)
MaterialApp has none of the router... named parameters you have typed here, so this code does not work.Strickle
Well then @macasas, the question should be invalid, because question also shouldn't have any "router... named parameters" as you strongly claimed :)Conciliar
I would have thought a question was allowed to be "wrong" and "invalid" because that's why the person is asking for help. I would have also thought it better to provide an answer that works. Providing an answer that doesn't work and then claiming you did it because the question doesn't work, sounds like you might be here for the wrong reasons, and as I see you have bounced all over this page telling others you don't "think" their answers work, I would "strongly" suggest you review your motivations.Strickle

© 2022 - 2024 — McMap. All rights reserved.