[proposal] feat(bloc): add mixins for common operations
- Dominant language
- Dart
- Stars
- 12.5k
- Forks
- 3.4k
- PR merge metrics
- No merged PRs in 30d
Description
Hi @felangel!
**Description**
There are a few common patterns that are used across `Bloc`s and `Cubit`s that require quite a few lines of boilerplate code and are error-prone.
They are related, but are not limited to: Bloc-to-Bloc/Cubit-to-Cubit/any other combination communications, Repository consumption (sending an event when a new entity is emitted by Repository), logging, and more.
Those patterns follow the same sequence of actions:
- Declare a private variable(s) that will be assigned in the initializer or throughout the lifecycle of a `Bloc` or `Cubit`
- Assign an object(s) that will be canceled/closed/disposed of in the `close` method
- Dispose of the object(s)
There are three main cases with that behavior:
1) Listening to a stream to perform any side effects
2) Reacting to stream with events (a subset of the first case)
3) Performing cancelable async operations (#3069)
**Desired Solution**
An elegant solution to that problem can be implemented through the help of mixins. For each case, the own mixin can be created.
1) `BlocListeningMixin` on `Closable` minimally containing `listenToStream` and `listenToStreamable` methods.
2) `BlocReactingMixin` on `BlocListeningMixin` and `BlocEventSink` minimally containing `reactToStream` and `reactToStreamable` methods.
3) `BlocAsyncMixin` on `Closable` minimally containing `cancelable` method.
Of course, those methods are only minimal content.
**Alternatives Considered**
An alternative will be to not change anything and keep track of cancelable objects by hand. That approach certainly works, but requires more code, is more error-prone, and requires more mental load on the developer.
**Additional Context**
A sample and rough implementation of `BlocListeningMixin` would look something like that. Note, that methods return an instance of `StreamSubscription` for cases when it should be canceled manually before the closing of the `Closable`.
```dart
mixin BlocListeningMixin on Closable {
final List> _subscriptions = [];
@protected
StreamSubscription listenToStream(
Stream stream,
void Function(T event) subscriber,
) {
final subscription = stream.listen(subscriber);
_subscriptions.add(subscription);
return subscription;
}
@protected
StreamSubscription listenToStreamable(
Streamable streamable,
void Function(T event) subscriber,
) =>
listenToStream(streamable.stream, subscriber);
@override
Future close() async {
for (final subscription in _subscriptions) {
await subscription.cancel();
}
return super.close();
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.