What is BLoC?
BLoC is a state management pattern created by Google. It separates business logic from UI components, making your code more modular and testable. The core idea is to use streams to manage the state, allowing you to react to state changes in a declarative way.
Why Use BLoC in Flutter?
- Separation of Concerns: BLoC helps you keep your business logic separate from UI code, promoting a clean architecture.
- Reusability: Since the business logic is isolated, it can be reused across different parts of the app or even in other projects.
- Testability: With BLoC, testing becomes easier as you can test business logic independently of the UI.
- Scalability: BLoC’s architecture is suitable for both small and large applications, ensuring maintainability as your app grows.
Core Concepts of BLoC
To implement BLoC in Flutter, you need to understand a few core concepts:
- Events: Events are inputs to the BLoC. They represent actions triggered by the user or system.
- States: States are outputs from the BLoC. They represent the current state of the UI based on the business logic.
- Streams: Streams are used to handle asynchronous data. BLoC uses streams to output states and receive events.
Implementing BLoC in Flutter
Let’s walk through a simple example to understand how BLoC works in Flutter. We’ll create a counter app where users can increment and decrement a counter.
Step 1: Add Dependencies
First, add the flutter_bloc
package to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.0
Step 2: Define Events
Create an abstract class CounterEvent
and extend it to define specific events:
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
Step 3: Define States
Create a class CounterState
to hold the state of the counter:
class CounterState {
final int counterValue;
CounterState({required this.counterValue});
}
Step 4: Create the BLoC
Create a class CounterBloc
that extends Bloc<CounterEvent, CounterState>
:
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(counterValue: 0));
@override
Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield CounterState(counterValue: state.counterValue + 1);
} else if (event is Decrement) {
yield CounterState(counterValue: state.counterValue - 1);
}
}
}
Step 5: Use BLoC in the UI
Now, use the CounterBloc
in your Flutter app:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterScreen(),
),
);
}
}
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Flutter BLoC Counter')),
body: Center(
child: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text(
'Counter Value: ${state.counterValue}',
style: TextStyle(fontSize: 24.0),
);
},
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => counterBloc.add(Increment()),
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () => counterBloc.add(Decrement()),
child: Icon(Icons.remove),
),
],
),
);
}
}