control_room 1.2.0
control_room: ^1.2.0 copied to clipboard
State Management for Flutter using Streams
Control Room #
A lightweight and efficient state management solution for Flutter applications based on Streams and InheritedWidgets.
Overview #
Control Room provides a structured architecture for managing application state by decoupling business logic from the user interface. It leverages Streams for reactive updates and InheritedWidgets for high-performance dependency injection and scoping.
Features #
- Decoupled Logic: Business logic is encapsulated within
StateControllerclasses. - Reactive UI: Automatic UI reconstruction via the
StateListenerwidget. - Granular Updates: Precise rebuild control using the
StateSelectorwidget. - Dependency Injection: Seamless access to controllers across the widget tree using
ControlRoom. - Resource Management: Automatic initialization and disposal of controllers to prevent memory leaks.
- Developer Friendly: Minimal boilerplate and a clean, predictable API.
Installation #
Add control_room to your pubspec.yaml file:
dependencies:
control_room: ^0.0.1
Core Concepts #
1. StateController #
The StateController is the base class for all business logic. It holds the current state and manages updates through a dedicated stream.
class CounterController extends StateController<int> {
CounterController() : super(0);
void increment() {
state++;
}
void decrement() {
state--;
}
}
2. ControlRoom Widget #
The ControlRoom widget serves as the provider for your controllers. It should be placed at the root of your application or at the top of a specific feature subtree.
void main() {
runApp(
ControlRoom(
controllers: {
CounterController: () => CounterController(),
SettingsController: () => SettingsController(),
},
child: const MyApp(),
),
);
}
3. StateListener #
The StateListener widget listens to state changes from a specific StateController and rebuilds its subtree whenever the state is updated.
StateListener<CounterController, int>(
builder: (context, count) {
return Text(
'Current Count: $count',
style: Theme.of(context).textTheme.headlineMedium,
);
},
)
4. StateSelector #
The StateSelector widget allows you to rebuild only when a specific part of the state changes. This is more efficient than StateListener when you have a large state object and only need to react to a subset of its properties.
StateSelector<CounterController, bool>(
selector: (controller) => controller.state > 10,
builder: (context, isLarge) {
return Text('Is count large? $isLarge');
},
)
5. Accessing Controllers #
You can access any registered controller from the widget tree using the ControlRoom.get<T>(context) method.
final controller = ControlRoom.get<CounterController>(context);
// Trigger actions
controller.increment();
Best Practices #
- Single Responsibility: Each
StateControllershould manage a specific piece of state or feature. - Granular Rebuilds: Use
StateListenerorStateSelectoras deep as possible in the widget tree to minimize the scope of rebuilds. - Performance: Prefer
StateSelectoroverStateListenerwhen you only need to rebuild for specific property changes. - Method Calls: Call controller methods from event handlers (e.g.,
onPressed) rather than during thebuildphase.
Example #
For a complete implementation including multi-page navigation and multiple controllers, please refer to the example directory in this repository.
License #
This project is licensed under the MIT License - see the LICENSE file for details.