Flutter – Access Bloc from parent on children

Issue

I have a parent widget that has two Blocs:

...
@override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<RestaurantBloc>(
          create: (BuildContext context) => RestaurantBloc(restaurantRepository: _restaurantRepository),
        ),
        BlocProvider<CartBloc>(
          create: (BuildContext context) => CartBloc(),
        ),
      ],
      child: RestaurantScreenWidget(),
    );
  }
...

Section of the parent widget where child widgets get generated using the CartBloc and other Bloc:

...
BlocBuilder<RestaurantBloc, RestaurantState>(
  builder: (context, state) {
    if (state is RestaurantEmpty) {
      return Center(
        child: Text('Empty'),
      );
    }

    if (state is RestaurantLoaded) {
      final items = state.restaurantCategories;

      if (items.length >= 1) {
        return BlocBuilder<CartBloc, CartState>(
          builder: (context, cartState) {
            return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <CategoryList>[
                for (var item in items)
                  CategoryList(categoryName: item.name, categoryItems: item.items)
              ],
            ); 
          },
        );
      }

      return Center(
        child: Text('Empty restaurant'),
      );
    }

    return Center(
      child: Text(
        'Error'
      ),
    );
  }
),
...

And then it generates various child widgets. Those widgets need access to CartBloc and its state:

...
Padding(
  padding: EdgeInsets.only(top: 20),
  child: SizedBox(
    width: double.infinity,
    child: BlocBuilder<CartBloc, CartState>(
      builder: (context, cartState) {
        return RaisedButton(
          child: const Text('ADD TO BASKET'),
            color: Colors.blue,
             textColor: Colors.white,
             onPressed: () {
               BlocProvider.of<CartBloc>(context).add(
                 AddItemToCart(
                   itemCount: (state as ItemLoaded).amount,
                   itemPrice: args.itemPrice,
                   newItemId: args.itemId,
                   newItemRestrictions: (state as ItemLoaded).restrictions,
                   newItemName: args.itemName
                 )
               );
               Navigator.pop(context);
             },
           );
         } 
       ), 
     ),
   ),
   ...

But by doing it like this, It gives the error:

enter image description here

However, if I put a MultiBlocProvider with the CartBloc on the child widgets, the error goes away, but obviously the parent widget doesn’t shares the state of the child widgets.

How can I handle the state that needs to be share between these two widgets? (The generate child widgets push to a screen that needs access to CartBloc and its state).

Solution

This is quite a common mistake. When using the BlocBuilder widget, you must give it the bloc instance to ‘build.’ You can do this by setting the optional "bloc" constructor property in the BlocBuilder.

BlocBuilder<CameraBloc, CameraState>(
  bloc: CameraBloc(),
  builder: (context, state) {
    if (state is InitialCameraState) {
      return Container(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: CameraPreview(controller)));
    }

    return Container();
  },
);

Answered By – Warren Snipes

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.