Rushdi Eskandar
Rushdi Eskandar

Reputation: 51

implementing bloc pattern with API cause an exception "type 'Future<dynamic>' is not a subtype of type 'Widget?'"

I am trying to implement bloc pattern in which I am using a repository class which consist all the methods which makes the calls with the API. On the other side I am implementing BlocBuilder to render the view based on bloc state however i am getting this error BlocBuilder<VehiclesBloc, VehiclesState>(dirty, dependencies: [_LocalizationsScope-[GlobalKey#df8d0]], state: _BlocBuilderBaseState<VehiclesBloc, VehiclesState>#dba40): type 'Future' is not a subtype of type 'Widget?'

I am really not sure where the issues comes from. here are some snippets of the code.

this is the bloc class which causes the error

  class VehiclesBloc extends Bloc<VehiclesEvent,VehiclesState>{
  VehiclesBloc(VehiclesState initialState) : super(initialState);

  @override
 Stream<VehiclesState> mapEventToState(VehiclesEvent event) async* {
 // TODO: implement mapEventToState
 if(event is LoadVehiclesList){
  yield* mapLoadEventToState(event);
 }
}

Stream<VehiclesState> mapLoadEventToState(LoadVehiclesList event) async* {
if(event is LoadVehiclesList){
  var response = await VehiclesService().getAll();
  if(response.IsSuccess){
   yield  VehiclesLoaded(response.Data);
  }else{
   yield VehiclesLoadingFailed(response.ErrorList.toString());
   }
  }else{
 yield VehiclesLoading();
 }
}

}

here is the Statefull widget which implements the Bloc Builder

   class VehicleList extends StatefulWidget {
   const VehicleList({Key key}) : super(key: key);
   static const String routeName = "/VehicleList";
  //final ScrollController scrollController;

  @override
 _VehicleListState createState() => _VehicleListState();
 }

class _VehicleListState extends State<VehicleList> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
VehiclesBloc vehiclesBloc = 
VehiclesBloc(VehiclesLoading())..add(LoadVehiclesList());

@override
void initState() {
 // TODO: implement initState
  super.initState();
 //VehiclesService().getAll();
}

  @override
  void dispose() {
  // TODO: implement dispose
   vehiclesBloc.close();
   super.dispose();
  }

 @override
  Widget build(BuildContext context) {
  final isRtl = context.locale.languageCode == "ar";
  return Scaffold(
    key: _scaffoldKey,
    backgroundColor: kBackgroundColor,
    drawer: SideNavigationDrawer(),
    body: Container(
      child: Column(
        children: [
          SizedBox(
            height: 15,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              IconButton(
                onPressed: () {
                  _scaffoldKey.currentState.openDrawer();
                },
                icon: Icon(
                  Icons.menu,
                  size: 35,
                  color: Colors.black,
                ),
              )
            ],
          ),
          Expanded(
            child: SingleChildScrollView(
              child: Column(
                children: [
                  BlocBuilder<VehiclesBloc,VehiclesState>(
                    builder: (context, state) {
                      if (state is VehiclesLoaded) {
                       // return BuildListVehicle(state.lsVehicle);
                        return Center();
                      } else if (state is VehiclesLoadingFailed) {
                        return Center(
                          child: CustomErrorWidget(),
                        );
                      } else {
                        return Center(
                          child: LoadingDialog.showLoadingDialog(context,
                              text: ""),
                        );
                      }
                    },
                    cubit: vehiclesBloc,
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    ));
  }   

Upvotes: 0

Views: 126

Answers (1)

mkobuolys
mkobuolys

Reputation: 5343

I think this code part causes the problem:

return Center(
  child: LoadingDialog.showLoadingDialog(context,text: ""),
);

Possibly, LoadingDialog.showLoadingDialog does not return a Widget but is just a function that returns Future.

For side effects (e.g. you want to show the dialog), you should use listeners instead of executing such code inside the build method. Instead of BlocBuilder, just use BlocConsumer and add the listener:

BlocConsumer<VehiclesBloc,VehiclesState>(
  listener: (context, state) {
    if (state is {your loading state}) {
      LoadingDialog.showLoadingDialog(context, text: "");
    }
  },
  builder: ...,
),

Some more insights about your code:

  1. Instead of creating BLoC as a variable in your stateful widget, use BlocProvider that would handle create/dispose part of your BLoC.
  2. Yield the VehiclesLoading state before loading the data and not just as an "else" case. This way you could handle the loading behaviour easily in your UI. To fix the above issues, just follow the documentation: https://bloclibrary.dev/

Upvotes: 0

Related Questions