LIVO - Live Object A model level state management solution for Flutter app
Flutter is great, but managing state can quickly become messy. You’ve probably used setState for small projects or Provider, Riverpod, or BLoC for bigger apps—but each comes with trade-offs.
⚠️ Note: This story was originally about reactive_orm, which is now deprecated. Its evolution is now called LIVO. LIVO continues its reactive object-relationship state management approach with improved naming, documentation, and long-term support.
Quick Concept Recap:
Objects = state models
Relationships = Many → One, Many ↔ Many
Reactive = automatic UI updates
Enter LIVO: a lightweight, reactive ORM-style state management library for Flutter.
It lets your UI react automatically when model properties change — no streams, ChangeNotifier, or boilerplate required.
With LIVO, you get:
Object-wise and field-wise reactivity
Nested and shared models
Many → One and Many ↔ Many relationships
Minimal boilerplate, plain Dart models

LIVO in action:
Object-wise: Update any field and rebuild the entire widget
Field-wise: Only rebuild widgets for selected fields
Many → One: Multiple models feeding a single observer
Many ↔ Many: Shared models reflected across multiple parents
Add LIVO to your project:
dependencies:
livo: <latest_version>import 'package:livo/livo.dart';class Task extends ReactiveModel {
String _title;
bool _completed = false;
String _status = "Idle"; Task({required String title}) : _title = title; String get title => _title;
set title(String value) {
if (_title != value) {
_title = value;
notifyListeners(#title); // ✅ Symbol-based
}
} bool get completed => _completed;
set completed(bool value) {
if (_completed != value) {
_completed = value;
notifyListeners(#completed);
}
} String get status => _status;
set status(String value) {
if (_status != value) {
_status = value;
notifyListeners(#status);
}
}
}✅ This is just plain Dart. LIVO will handle notifying widgets when fields change.
final objectWise = Task(title: "Object-wise Reactivity");ReactiveBuilder<Task>(
model: objectWise,
builder: (task) {
return ListTile(
title: Text(task.title),
subtitle: Text(task.status),
trailing: Checkbox(
value: task.completed,
onChanged: (v) => task.completed = v!,
),
);
},
);Here, checking the checkbox triggers a rebuild of the entire widget.
Sometimes, you only want specific fields to trigger a rebuild:
final fieldWise = Task(title: "Field-wise Reactivity");ReactiveBuilder<Task>(
model: fieldWise,
fields: [#completed, #status],
builder: (task) {
return ListTile(
title: Text(task.title),
subtitle: Text(task.status),
trailing: Checkbox(
value: task.completed,
onChanged: (v) => task.completed = v!,
),
);
},
)✅ Only changes to completed or status rebuild the widget. Other fields are ignored.
Combine multiple models into a single reactive observer:
class Dashboard extends ReactiveModel {
final List<Task> sources; Dashboard(this.sources) {
for (final task in sources) {
addNested(task); // listen to many
}
}
}final manyA = Task(title: "Task A");
final manyB = Task(title: "Task B");
final dashboard = Dashboard([manyA, manyB]);ReactiveBuilder<Dashboard>(
model: dashboard,
builder: (_) => Column(
children: [
Text("A: ${manyA.completed}"),
Text("B: ${manyB.completed}"),
],
),
);Updating manyA or manyB automatically rebuilds the dashboard widget.
Models can be shared across multiple parents, keeping the UI in sync everywhere:
class Group extends ReactiveModel {
final String name;
final List<Task> tasks; Group({required this.name, required this.tasks}) {
for (final task in tasks) addNested(task);
}
}final group1 = Group(name: "Group 1", tasks: [objectWise, fieldWise]);
final group2 = Group(name: "Group 2", tasks: [fieldWise, manyA]);ReactiveBuilder<Group>(
model: group1,
builder: (g) => Column(
children: g.tasks.map((t) => Text("• ${t.title} → ${t.completed}")).toList(),
),
);✅ Updating a task reflects automatically across all groups that include it.
Models extend ReactiveModel
Field setters call notifyListeners(#field) whenever a value changes
ReactiveBuilder widgets listen to either the whole object or specific fields
Nested models propagate changes upward automatically
No streams. No manual wiring. Everything updates safely and efficiently.
Clean Dart models with minimal boilerplate
Fine-grained reactivity for optimized performance
ORM-style mental model for easier app design
Works seamlessly for single fields, nested models, or shared models
Pub Package: LIVO
💡 Tip for Readers
Start small: use object-wise for quick prototyping. As your app grows, switch to field-wise or nested models for efficiency.
1
5
0