2
votes

I am new to the BLoC pattern, and a question has arisen that I have not been able to find elsewhere. Using the flutter_bloc library, I have access to a BlocBuilder widget which will rebuild whenever there is a change in the BLoC's state. Since I am handling state independent of the framework, is it necessary to declare the parent widget (say a Card that contains data from a BLoC) as Stateful?

I have been able to successfully implement BlocBuilders as children of both Stateful and Stateless widgets, but I haven't been able to decide which would be best practice, or if there would be any case at all in which being Stateful would be necessary.

I think I would be on the right track to say that Stateless is fine if you don't need to update anything outside of the BlocBuilder, but you would need Stateful if you were to add something like a RefreshIndicator and had to implement logic for that (and conditionally pass events to the BLoC). Is that correct?

I'm sure I am over-explaining here, but in the spirit of that, I have provided some code below if it aids the understanding of my question.

Here is a simplified Stateless implementation that pertains to my project:


class WeatherCard extends StatelessWidget {

  /// You can assume that the following is happening:
  ///   1) There is a BlocProvider in the parent widget which
  ///      will implement this WeatherCard.
  ///
  ///   2) The WeatherLoaded state in the WeatherBloc provides an 
  ///      instance of a WeatherModel which contains all of the data
  ///      from a weather API.
  ///

  @override
  Widget build(BuildContext context) {
    return Card(
      child: BlocBuilder(
        bloc: BlocProvider.of<WeatherBloc>(context),
        builder: (BuildContext context, WeatherState state) {
          if (state is WeatherLoading) {
            return Text('Loading...');
          } else if (state is WeatherLoaded) {
            return Text(state.weatherModel.temp.toString());
          } else {
            return Text('Error!');
          }
        }
    );
  }
}

And the Stateful implementation:


// You can make the same assumptions here as in the Stateless implementation.

class WeatherCard extends StatefulWidget {
  @override
  _WeatherCardState createState() => _WeatherCardState();
}

class _WeatherCardState extends State<WeatherCard> {
  @override
  Widget build(BuildContext context) {
    return Card(
      child: BlocBuilder(
        bloc: BlocProvider.of<WeatherBloc>(context),
        builder: (BuildContext context, WeatherState state) {
          if (state is WeatherLoading) {
            return Text('Loading...');
          } else if (state is WeatherLoaded) {
            return Text(state.weatherModel.temp.toString());
          } else {
            return Text('Error!');
          }
        }
    );
  }
}


1

1 Answers

5
votes

By using Bloc, you should be able to avoid declaring Stateful widgets almost entirely, although it is certainly possible and sometimes it makes sense to use stateful widgets or other state management strategies also.

If you are conditionally passing logic to the bloc, you may want to consider moving the conditional logic to the bloc itself and just pass the events which trigger the conditionals.

It is also definitely possible to have multiple Streams declared in the bloc and multiple StreamBuilders in the UI listening to the same Bloc, though I don't know whether that is possible with the flutter_bloc library. It looks like you are restricted to a single Stream per bloc if you are using flutter_bloc. You can also use the strategy/BlocProvider described here instead.

For some small change in the UI that doesn't have any/much affect the program's logic, it may be easier to use a stateful widget to handle the state than to keep the state in the Bloc. There isn't really a right or wrong answer for all situations, it is up to you to decide what will be easier to build and maintain in the long run. But your program will probably be easier to read and easier to find what you want to change if you keep your architecture consistent. So, if you are using bloc, that would mean handle all state in Blocs and build your UI entirely, or almost entirely, out of stateless widgets.