In the Flutter Bloc Essential course, you can learn in depth about Bloc, the popular Flutter state management solutions.
In particular, it covers only the most recent version, version 8.0 or higher.
If you want to deepen your understanding of the Flutter Bloc and put all the concepts into practice, then this course is for you.
The lecture was carefully composed to ensure a balance between theory and practice.
And under the belief that repetition is the most important learning method, whenever there is a new concept, we will test the concept by making a small app, and through real-world apps such as TODO, Weather, and Firebase Authentication app, the concepts will come together comprehensively.
Few common widgets from the flutter_bloc
package:
BlocBuilder<BlocA, BlocAState>(
bloc: blocA, // provide the local bloc instance
buildWhen: (previousState, state){
// return true/false to determine whether or not
// to rebuild the widget with state
},
builder:(context, state){
// return widget here based on BlocA's state
}
)
BlocListener<BlocA, BlocAState>(
bloc: blocA, // provide the local bloc instance
listenWhen: (previousState, state){
// return true/false to determine whether or not
// to call listener with state
},
listener:(context, state){
// do stuff here based on BlocA's state
},
child: Container(),
)
It is the combination of BlocBuilder
& BlocListener
BlocConsumer<BlocA, BlocAState>(
bloc: blocA, // provide the local bloc instance
listenWhen: (previousState, current){
// return true/false to determine whether or not
// to call listener with state
},
listener:(context, state){
// do stuff here based on BlocA's state
},
buildWhen: (previousState, current){
// return true/false to determine whether or not
// to rebuild the widget with state
},
builder:(BuildContext context, BlocAState state){
// return widget here based on BlocA's state
}
)
When we needed to use multiple states at the same time, then we should use these extensions for code readability.
◉ context.watch<T>(), which makes the widget listen to change on T
◉ context.read<T>(), which returns T without listening to it
◉ context.select<T, R>(R cb(T value)), which allows a widget to listen
to only a small part of T.
BlocProvider.of<T>(context) = context.read<T>()
BlocProvider.of<T>(context, listen: true) = context.watch<T>()
Step-by-step process for creating a cubit/bloc:
1. create ClassState
2. create variable
3. Generate `Constructor`
4. ClassState `extends` Equatable
5. Generate `Equitable`
6. Generate `toString()`
7. Generate `copyWith()`
8. write `factory` contactor (i.e. CounterState.initial())
Cubit to Cubit & Bloc to Bloc communication can be developed using:
◉ cubit + StreamSubscription
◉ cubit + BlocListener
◉ bloc + StreamSubscription
◉ bloc + BlocListener
1. Anonymous Route Access
2. Named Route Access
3. Generated Route Access
import 'package:bloc/bloc.dart';
class CounterBlocObserver extends BlocObserver {
@override
void onEvent(Bloc bloc, Object? event) {
super.onEvent(bloc, event);
print('ColorBlocObserver(event): ${bloc.runtimeType}, $event');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
print('ColorBlocObserver(error): ${bloc.runtimeType}, $error, $stackTrace');
super.onError(bloc, error, stackTrace);
}
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('ColorBlocObserver(change): ${bloc.runtimeType}, $change');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print('ColorBlocObserver(transition): ${bloc.runtimeType}, $transition');
}
}
How to implement it in the main function?
void main() {
/// this [Bloc.observer] is only of `debugging` purpose
///
Bloc.observer = ColorBlocObserver();
runApp(const MyApp());
}
Bloc 7.2.0 and Bloc 8.0.0 introduce a new way to register event handlers. With this change comes several benefits, including reduced boilerplate, better consistency with cubit, and, most of all, concurrent event processing — by default!
Note: Read the detailed documentation of Event Transformation
dependencies:
equatable: ^2.0.5
# For state management
bloc: ^8.1.0
flutter_bloc: ^8.1.1
# For Event Transform
bloc_concurrency: ^0.2.0
- Independent States
- Computed States
- StreamSubscription
- BlocListener
-
Make the state as atomic as possible
- If it can logically separated, create a separate state and manage it
-
State is mainly managed in the form of a class
- Group and manage logically related values
- Classify and manage primitive type variables such as String and int - The advantage of avoiding type conflicts
-
Immutable state
- Create a new state using the copyWith function
-
Always extends Equatable class
- Ease of equality check of object instances
- Provides convenience functions such as stringify