Nithin Sai
Nithin Sai

Reputation: 1013

Flutter could not find the correct Provider above BlocConsumer Widget

I'm using Flutter Bloc for a project.

This is the structure:

      MultiBlocProvider(
          providers: [
            BlocProvider<BlocA>(
              create: (context) {
                return BlocA()
                  ..add(FetchEvent());
              },
            ),
            BlocProvider<BlocC>(
              create: (context) {
                return BlocC()..add(FetchEvent());
              },
            ),
          ],
          child: IndexedStack(
            index: _pageNum,
            children: [
              ChildA(),
              ChildB(),
            ],
          ),
        )

Inside ChildB I have a Navigator.push() to a ChildC, where BlocC is being used (BlocConsumer), but I'm getting an error,

Flutter could not find the correct Provider above BlocConsumer<BlocC> Widget

Edit There is a button in ChildB that navigates to ChildC on pressed. Like,

TextButton( // this code exists inside a scaffold widget
   child: Text("Page C"),
   onPressed: () {
      Navigator.push(context, CupertinoPageRoute(builder: (context) => ChildC()));
   }
), 

This is the bloc consumer in ChildC

// Child C
 Scaffold(
      body: BlocConsumer<BlocC, CState>(
        builder: (context, state) {
          if(state is CSuccessState) {
            return _body();
          } else if (state is CLoadingState || state is CInitState) {
            return Center(child: CircularProgressIndicator());
          } else return Center(child: Text("Something went wrong"));
        },
        listener: (context, state) {},

      ),
    );

Edit 2

I found this answer, apparently, this is an issue when using Navigator.push. Still, if anyone knows how to solve it in my case, do let me know

Upvotes: 3

Views: 2292

Answers (2)

Valentin Vignal
Valentin Vignal

Reputation: 8202

Provider is scoped. It means only the subtree of your provider (your child widgets) can access it. When you push a new page, it pushed it to the MaterialApp router (default root router of your app), and your widget tree looks like:

MaterialApp
 |- Provider
 |   |- TextButton (with onPressed: () => Navigator.push())
 |- ChildC

As you can see, your ChildC is not below the Provider(s).


1. Move your providers above your material app

A way to solve it is to move your providers above your MaterialApp:

Provider
 |- MaterialApp
 |   |- TextButton (with onPressed: () => Navigator.push())
 |   |- ChildC

2. Use nested routers

You can push your page to a nested router that is below your Provider:

MaterialApp
 |- Provider
 |   |- Router
 |   |  |- TextButton (with onPressed: () => Navigator.push())
 |   |  |- ChildC

3. Provide again your BlockC above ChildC :

TextButton( // this code exists inside a scaffold widget
   child: Text("Page C"),
   onPressed: () {
      final blockCValue = context.read<BlockC>();
      Navigator.push(
        context,
        CupertinoPageRoute(builder: (context) => Provider<BlockC>.value(
          value: blockCValue,
          child: ChildC(),
        ),
      );
   },
), 

Upvotes: 6

Rahul
Rahul

Reputation: 5049

The Navigator's behaviour is expected.

You should replace Navigator.push(context, CupertinoPageRoute(builder: (context) => ChildC())); with

Navigator.push(context, CupertinoPageRoute(builder: (ctx) => BlocProvider.value(value: context.read<BlocC>()), child: ChildC());

This will work.

Upvotes: 1

Related Questions