In this project we will learn what is Bloc and how to use it by practical examples provided in
https://bloclibrary.dev/#/coreconcepts
Read more on https://dart.dev/tutorials/language/streams
- Streams provide an asynchronous sequence of data
- Data sequences include user-generated events and data read from files.
- You can process a stream using either await for or listen() from the Stream API
- Streams provide a way to respond to errors.
- There are two kinds of streams: single subscription or broadcast
In short: A stream is a sequence of asynchronous events. It is like an asynchronous Iterable—where, instead of getting the next event when you ask for it, the stream tells you that there is an event when it is ready.
Streams can be created in many ways, which is a topic for another article, but they can all be used in the same way: the asynchronous for loop (commonly just called await for) iterates over the events of a stream like the for loop iterates over an Iterable. For example:
Future<int> sumStream(Stream<int> stream) async {
int sum = 0;
// await for stream and perform sum operation on stream value
await for (int value in stream) {
sum += value;
// if you want to see the stream value.
print("sum: $sum, stream: $value");
}
return sum;
}
// async* allow us to use yield keyword and return `Stream` of data.
Stream<int> countStream(int max) async* {
for (int i = 0; i < max; i++) {
// yield push value of i through `stream`
yield i;
}
}
void main() async {
/// Initialize a stream of integers 0-9
Stream<int> stream = countStream(10);
/// Compute the sum of the stream of integers
int sum = await sumStream(stream);
/// Print the sum
print(sum); //
}
- A cubit is a class which extends
BlocBase
and can be extended to manage any type of state.
- A cubit can expose functions which can be invoke to trigger state changes.
example
/// define cubit and specify type of the state
/// in this case it is int. for complex states,
/// use Class e.g: User, Wallet, Category, Transaction, etc
class CounterCubit extends Cubit<int> {
/// initial state is 0
CounterCubit(): super(0);
/// Or we can also accept external value
// CounterCubit(int initialState): super(initialState);
/// external state value can be set like this:
// final cubitA = CounterCubit(0);
// final cubitB = CounterCubit(10);
}
- Each
cubit
has the ability to o/p a new state viaemit
.
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}
void main() {
final cubit = CounterCubit();
print(cubit.state) // 0 (initial state)
cubit.increment();
print(cubit.state); // 1 (incremented state)
cubit.close();
}
Cubit
exposes aStream
which allow us to receive real-time state updates:
Future<void> main() async {
final cubit = CounterCubit();
final subscription = cubit.stream.listen(print); // 1
cubit.increment();
await Future.delayed(Duration.zero);
await subscription.cancel();
await cubit.close();
}
In the above snippet, we are subscribing to the CounterCubit
and calling print on each state change. We are then invoking the increment
function which will emit a new state. Lastly, we are calling cancel
on the subscription
when we no longer want to receive updates and closing the cubit
.
Whan a Cubit
emits a new state, a Change
occurs. We can observe all changes for a given Cubit
by overriding onChange
.
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
// Observing a cubit
@override
void onChange(Change<int> change) {
super.onChange(change);
print(change);
}
// Error Handling
@override
void onError(Object error, StackTrace stackTrace) {
print('$error, $stackTrace');
super.onError(error, stackTrace);
}
// we can then interact with the `Cubit` and observe all changes output to the console.
void main() {
CounterCubit()
..increment()
..close();
}
}
// example output
// > Change { currentState: 0, nextState: 1 }
https://bloclibrary.dev/#/coreconcepts https://dart.dev/tutorials/language/streams