In Flutter, BLoC stands for Business Logic Component.
It's an architectural pattern that helps
separate the business logic from the UI. This separation makes your Flutter apps more
maintainable, testable, and scalable.
You mentioned you prefer not to use third-party packages—so let’s explore BLoC from first
principles without relying on the flutter_bloc package.
---
🔧 What Is BLoC in Flutter?
BLoC is a state management approach based on:
Streams (using Dart's Stream and Sink)
Events (input to the BLoC)
States (output from the BLoC)
The BLoC listens to incoming events via a stream, processes them (i.e., contains the business
logic), and then emits new states through another stream.
---
🧱 BLoC Structure (Without Third-Party Packages)
You’ll generally have:
1. Event class (what user or system sends)
2. State class (what UI listens to)
3. BLoC class (handles logic and streams)
4. UI (typically a StatefulWidget or StreamBuilder)
---
📦 Example: Counter BLoC
1. Events
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
2. States
class CounterState {
final int count;
CounterState(this.count);
}
3. BLoC Class
import 'dart:async';
class CounterBloc {
int _count = 0;
final _stateController = StreamController<CounterState>();
Stream<CounterState> get state => _stateController.stream;
final _eventController = StreamController<CounterEvent>();
Sink<CounterEvent> get eventSink => _eventController.sink;
CounterBloc() {
_eventController.stream.listen(_mapEventToState);
}
void _mapEventToState(CounterEvent event) {
if (event is Increment) {
_count++;
} else if (event is Decrement) {
_count--;
}
_stateController.sink.add(CounterState(_count));
}
void dispose() {
_stateController.close();
_eventController.close();
}
}
4. UI Code
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
final bloc = CounterBloc();
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter BLoC')),
body: StreamBuilder<CounterState>(
stream: bloc.state,
initialData: CounterState(0),
builder: (context, snapshot) {
return Center(
child: Text('Count: ${snapshot.data!.count}',
style: TextStyle(fontSize: 30),
),
);
},
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => bloc.eventSink.add(Increment()),
child: Icon(Icons.add),
),
SizedBox(width: 10),
FloatingActionButton(
onPressed: () => bloc.eventSink.add(Decrement()),
child: Icon(Icons.remove),
),
],
),
);
}
}
---
✅ Advantages of BLoC
Complete separation of UI and business logic
Works well with unit testing
Uses native Dart Stream API (no need for third-party packages)
Scalable for complex apps
---
If you're interested, I can also help you write a small Flutter app with multiple BLoCs and without
external packages like flutter_bloc. Just let me know!