skip to Main Content

I am using a BlockProvider to manage the AuthService of my app and I’m currently working on a Setting Menu where there are some configurations that involve using this BlocProvider.

This BlocProvider is bein invoked in the MaterialApp func:

MaterialApp(
...
home: BlocProvider<AuthBloc>(
        create: (context) => AuthBloc(FirebaseAuthProvider()),
        child: const HomePage(),
      ),
...
),

My HomePage() ensures the AuthState:

...
return BlocBuilder<AuthBloc, AuthState>(
          builder: (context, state) {
            if (state is LoggedInAuthState) {
              return const InitialView();
            } else if (state is RegisteringAuthState) {
...

And then in the InitialView theres this AppBar in the Scaffold where the Button user the Navigator.of(context) to push the config menu:

AppBar(
        actions: [
          IconButton(
              onPressed: () async {
                Navigator.of(context).pushNamed(configRoute);
              },
              icon: const Icon(Icons.settings)),
        ],
      )

Now in the config menu:

 //! NO FUNCIONA
 TextButton(onPressed: () {
     context.read<AuthBloc>().add(
       const LogOutAuthEvent(),
     );
 }, child: Text(context.loc.logout))

When pressing the button an Error is thrown:
Error: Could not find the correct Provider above this SettingsMenu Widget

I tried to set this same button in my InitialView() and it works, so it has to do something with the Navigator.

2

Answers


  1. The issue here is that when you navigate to a new route, the BlocProvider needs to be accessible in the new route’s widget tree. To pass the existing AuthBloc to the SettingsMenu when navigating, you can use BlocProvider.value to provide the current instance of AuthBloc to the new route.

    Here is how you can modify your navigation call:

    IconButton(
      onPressed: () {
         Navigator.of(context).push(
         MaterialPageRoute(
            builder: (context) {
               return BlocProvider.value(
                  value: BlocProvider.of<AuthBloc>(context),
                  child: SettingsMenu(), // Your settings menu widget
               );
            },
         ));
       },
       icon: const Icon(Icons.settings),
    )
    
    Login or Signup to reply.
  2. Once you’re pushing a new page onto the stack, you are working within a new context. You can pass on the instance of the bloc as a variable to the new page and use that in children of that. This can become very serious boilerplate once you reach a certain complexity.

    The solution to that is to simply move your provider to be the parent to MaterialApp. The bloc is now available in the whole context of that. Below Code uses a MultiBlocProvider, since you often have more than one Provider you want to have available globally.

    MultiBlocProvider(providers: [
              BlocProvider<AuthBloc>.value(value: AuthBloc(FirebaseAuthProvider()),
            ], child: MaterialApp(...)),
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search