Bloc Pattern
1. Why Bloc
- Keep your code clarm organized, clean, and maintainable
- Compatible with flutter declarative programming
2. What's Bloc
- A design pattern created by Google to separate Logic from UI
- There is many library to implement this design pattern. But IMO, you should use the flutter_bloc of Felix Angelo. It is a state management to easier your life
- For every action inside the application, there will be a relative state from it. For example, when the data is fetching, the app should be in a loading state displaying a loading animation on the screen
3. The Core Concepts
- Stream is the foundation of Bloc
3.1 Stream
- Stream is a sequence of async event. Each event is a data event or error event.
- When a stream has dispatched its event, it will also notify to all listener subscribed to it
3.2 Receive Stream
- async* means asynchronous generation function, it generates async data
- yield pushes the data (integer) through the Stream
- await keyword helps to wait for a process to finish before proceeding to the next step
```
Stream<int> dataStream() async* {
for (int i = 0; i<3; i++) {
await Future.delayed(Duration(seconds:3));
yield i;
}
}
Stream<int> stream = dataStream();
stream.listen((event) {
print("RECEIVE data ${event.toString()}");
});
```
- async* means asynchronous generation function, it generates async data
- yield pushes the data (integer) through the Stream
- await keyword helps to wait for a process to finish before proceeding to the next step
3.3 Cubit and Bloc
- Cubit is a minimal version of Bloc
- Cubit only emits a stream of states
- Bloc emits a stream of states and receive a stream of event
4. Flutter BLOC
4.1 BlocProvider
- A widget that creates and provides a Bloc to all of its children. A single instance of it can be provided to multi widgets within a tree hierarchy
4.2 Bloc Builder
- BlocBuilder is a widget that helps rebuild the UI based on some Bloc state
changes
- Rebuild a large UI is a heavy cpu task to compute. That's why you need to wrap the exact part of the UI you want to rebuild inside BlocBuilder. For example, if a text is nested inside a column or a row, dont build entire the column/ row, rather to rebuild the text widge only by wrapping it inside the BlocBuilder
- If you dont provide exactly the cubit/ Bloc in Blocbuilder, it will search for the nearest parent bloc in the tree
5. Code Implementation
counter_app.dart
```
import 'package:flutter/material.dart';
import 'counter/counter.dart';
class CounterApp extends MaterialApp {
const CounterApp({Key? key}) : super(key: key, home: const CounterPage());
}
```
counter_page.dart
```
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../counter.dart';
import 'counter_view.dart';
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterCubit(),
child: CounterView(),
);
}
}
```
counter_cubit.dart
```
import 'package:bloc/bloc.dart';
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
/// Add 1 to the current state.
void increment() => emit(state + 1);
/// Subtract 1 from the current state.
void decrement() => emit(state - 1);
}
```
counter_view.dart
```
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../counter.dart';
class CounterView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, state) {
return Text('$state', style: textTheme.headline2);
},
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
key: const Key('counterView_increment_floatingActionButton'),
child: const Icon(Icons.add),
onPressed: () => context.read<CounterCubit>().increment(),
),
const SizedBox(height: 8),
FloatingActionButton(
key: const Key('counterView_decrement_floatingActionButton'),
child: const Icon(Icons.remove),
onPressed: () => context.read<CounterCubit>().decrement(),
),
],
),
);
}
}
```
6. Summary
- Bloc is a good pattern to improve the code quality and help easier the state management in app
- Must familiar with stream and reactive programming
- Much of boilerplate code
Reference link:
- https://bloclibrary.dev/#/gettingstarted