Search code examples
flutterblocflutter-bloc

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


Solution

  • 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(),
            ),
          );
       },
    ),