Diego Francisco
Diego Francisco

Reputation: 1910

Flutter - Access Bloc from parent on children

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).

Upvotes: 1

Views: 8335

Answers (2)

Michael Wang
Michael Wang

Reputation: 463

In the parent widget (the one with MultiBlocProvider), wrap RestaurantScreenWidget with Builder.

Upvotes: 0

Warren Snipes
Warren Snipes

Reputation: 198

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

Upvotes: 4

Related Questions