Search code examples
flutterblocstate-management

why can't we use BlocProvider.of(blocContext) inside of Consumer with bloc attribute? and what is the solution?


inside of a build method:

  return BlocBuilder<UserCubit, UserState>(
    bloc: UserCubit("firstName", "lastName"),
    builder: (BuildContext blocContext, UserState state) {
                  print(BlocProvider.of<UserCubit>(blocContext).user.fullName);  // error here
});

error:

BlocProvider.of() called with a context that does not contain a UserCubit.

which is obviously not the case...

the question is, how can I access the cubit in case of BlocBuilder/BlocConsumer where bloc attribute is not null.


Solution

  • Basically it is because the widget BlocBuilder is not injecting the provided bloc parameter in your BuildContext blocContext.

    The flutter_bloc documentation says that that BlocBuilder is working like a StreamBuilder, it is not injecting anything in your widget tree it will only "listen" to your provided UserCubit in the bloc property. And because UserCubit is not injected in your widget tree you won't ever be able to access it by using BlocProvider.

    BlocBuilder handles building a widget in response to new states. BlocBuilder is analogous to StreamBuilder but has simplified API to reduce the amount of boilerplate code needed as well as bloc-specific performance improvements.

    When you are using a BlocBuilder you will need to rely on the state value to access properties from your bloc or cubit and you will have to inject your bloc/cubit in the widget tree by using a parent BlocProvider, here's an example:

    class MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final userCubit = UserCubit("firstName", "lastName");
    
        // Using BlocProvider to inject your UserCubit
        return BlocProvider(
          create: (_) => userCubit,
          child: BlocBuilder<UserCubit, UserState>(
            // Still using the instance of userCubit as the injected instance is not
            // available in the widget tree at this point.
            bloc: userCubit,
            builder: (blocContext, state) {
              // Now that you are in your builder with an up-to-date blocContext you can
              // have access to your instance of UserCubit with BlocProvider.
              print(BlocProvider.of<UserCubit>(blocContext).user.fullName);
              return Text("State is $state");
            },
          ),
        );
      }
    }
    

    You can try the full example on DartPad