Is your feature request related to a problem? Please describe.
I often find myself in the situation where I need both bloc builders and bloc listeners in the same widget tree, e.g. for showing a loading indicator (builder) and displaying a snackbar on success (listener).
Describe the solution you'd like
A BlocBuilderListener Widget that accepts both a builder function and a listener would greatly reduce the clutter in my code and also reduce the overhead of having two stateful widgets that basically do the same. Alternatively, you could add a listener parameter to the existing BlocBuilder widget.
Hi @fl0cke 👋
Thanks for opening an issue!
Can you please elaborate a bit on why you say this would reduce the clutter in your code?
If I'm understanding correctly, you're proposing to go from:
BlocListener<MyBloc, MyState>(
listener: (context, state) { ... },
child: BlocBuilder<MyBloc, MyState>(
builder: (context, state) { ... }
),
),
to
BlocBuilderListener<MyBloc, MyState>(
listener: (context, state) { ... },
builder: (context, state) { ... },
),
I personally don't think it's cluttered as is and I'd be more concerned about confusing people because it isn't immediately obvious what BlocBuilderListener
would do.
Thoughts?
Hey @felangel,
Thanks for the quick reply!
Yes, that's exactly what the proposed BlocBuilderListener would look like. Alternatively, we could add an optional listener
parameter to the BlocBuilder
to avoid introducing a new widget.
I agree that it's not that much clutter, but when i look at my usage of the two BlocX widgets, i often find myself using either just a BlocBuilder
or a BlocBuilder
nested in a BlocListener
, but almost never a BlocListener
on its own. So this would be good opportunity to reduce the number of widgets that are required to achieve a reactive UI + side effects.
Example: A common use case is submitting some sort of user input and displaying a loading indicator while doing so. On success, I want to both show a SnackBar (using the listener) and hide the loading indicator (i.e. rebuild the UI using the builder).
However, I'm also just getting started with BLOC so you probably know better what's good for the library 👍
I would suggest the merge to have the same signature as ListView
and ListView.builder
e.g.
//normal BlocListener, listener is triggered on state change, child doesn't get rebuilt on state change
BlocView<MyBloc,MyState>(
listener: (context, state) { ... },
child: Container()
)
//works as BLocBuilder and BlocListener combined, listener and builder get triggered on state change
BlocView<MyBloc,MyState>.builder(
listener: (context, state) { ... }, //listener here is optional
builder: (context, state) { ... },
)
(this also goes well with my proposal here https://github.com/felangel/bloc/issues/560)
e.g.
BlocView<MyBloc>(
listener: (context, state) { ... },
child: Container()
)
BlocView<MyBloc>.builder(
listener: (context, state) { ... }, //listener here is optional
builder: (context, state) { ... },
)
now we can also take this to the next level by listening to multiple Bloc
s
BlocView<BlocA,BlocB,BlocC>(
listener: (context, stateA,stateB,stateC) { ... },
child: Container()
)
BlocView<BlocA,BlocB,BlocC>.builder(
listener: (context, stateA,stateB,stateC) { ... }, //listener here is optional
builder: (context, stateA,stateB,stateC) { ... },
)
I agree that
Hey @felangel,
Thanks for the quick reply!Yes, that's exactly what the proposed BlocBuilderListener would look like. Alternatively, we could add an optional
listener
parameter to theBlocBuilder
to avoid introducing a new widget.I agree that it's not that much clutter, but when i look at my usage of the two BlocX widgets, i often find myself using either just a
BlocBuilder
or aBlocBuilder
nested in aBlocListener
, but almost never aBlocListener
on its own. So this would be good opportunity to reduce the number of widgets that are required to achieve a reactive UI + side effects.Example: A common use case is submitting some sort of user input and displaying a loading indicator while doing so. On success, I want to both show a SnackBar (using the listener) and hide the loading indicator (i.e. rebuild the UI using the builder).
However, I'm also just getting started with BLOC so you probably know better what's good for the library 👍
I agree that reducing unnecessary nesting would be preferable. I do like the idea of adding an optional listener parameter to the bloc builder. I agree with you @felangel that building a separate BlocBuilderListener could get confusing.
I definitely think that the listener
should be added to the BlocBuilder
or BlocView
, whatever you prefer as a name. You would only have to differentiate the build/listen condition, which could be two separate params like buildWhen
and listenWhen
. A lot cleaner approach and extremely helpful overall.
@RollyPeres but you’d also still have a separate BlocListener in cases where you only want to listen?
That or make the builder
optional. e.g.: assert(builder != null || listener != null)
. But that would probably require a name change to something more generic not strictly tied to building, maybe BlocView
or something.
BlocView still implies there is a view so it also wouldn’t make sense to have an optional builder imo. I personally don’t want to over complicate and muddy the role of BlocBuilder which is why I’ve been hesitant to introduce this. The benefit of introducing this is not that significant imo. Thoughts?
I agree in regards to naming, I just threw in the name which @bigworld12 came up with for the sake of example. Well, I also understand there are many of your users already comfortable with the current state of this library. The smartest way to go about this would probably be to keep those two widgets as they are and introduce a new one which combines the two together and let users pick and choose ✌
Yeah that’s what I was leaning toward as well but not sure what a good, obvious name would be 🤔
BlocConsumer
? RIP Remi's naming conventions 👍
That could work haha. I’ll think about it some more and discuss with the team 👍
Just a few additional names to consider are BlocReceiver and BlocRetriever.
I think also linguistically it feels like something that Provides aka a "BlocProvider" should be matched with something that receives or retrieves. Once a Bloc is received or retrieved, anything could be done with it such as building a widget or listening to the bloc to perform another task. This naming convention could potentially make it easier to add additional functionality in the future through the use of optional parameters.
A consumer linguistically feels more opposite to a "producer" rather than a "provider." BlocConsumer however may fit already more familiar naming conventions with Dart/Flutter.
I also considered BlocClient but that seems a little less intuitive to me as something that receives from a BlocProvider. It feels more appropriate that a BlocClient would be opposite to a BlocServer to fit more traditional naming conventions.
Since bloc
has a small flavor of redux, I'll also nominate BlocConnector
.
I think just BlocWidget makes sense as far as BLoC pattern goes, b-logic classes represented by Bloc
Implemented in #753 and released in flutter_bloc v3.1.0
🎉
Most helpful comment
Implemented in #753 and released in
flutter_bloc v3.1.0
🎉