reactive_flutter 1.0.2
reactive_flutter: ^1.0.2 copied to clipboard
A lightweight auto-tracking reactive state management library for Flutter.

- About
- Features
- Installation
- Reactive State
- Watch Widget
- Dependency Injection
- Page-Based Pagination
- Cursor-Based Pagination
- Architecture
- Performance
- Comparison
- Advanced Examples
- Unit Testing
- FAQ
- Roadmap
- Contributing
- Changelog
- License
About #
A lightweight auto-tracking reactive state management library for Flutter.
reactive_flutter provides:
- Reactive state containers
- Automatic widget rebuild tracking
- Lightweight dependency injection
- Page-based pagination
- Cursor-based pagination
- Minimal boilerplate
- Zero code generation
Features #
✅ Automatic dependency tracking
✅ Lightweight and fast
✅ No BuildContext required for state access
✅ No manual dependency lists
✅ Page-based pagination
✅ Cursor-based pagination
✅ Simple dependency injection
✅ Easy to learn and use
Installation #
Add the package to your pubspec.yaml:
dependencies:
reactive_flutter: latest_version
Then run:
flutter pub get
Import the package:
import 'package:reactive_flutter/reactive_flutter.dart';
Reactive State #
Reactive<T> is a lightweight reactive value holder.
Whenever the value changes, widgets that depend on it automatically rebuild.
Create Reactive Values #
final Reactive<int> counter = Reactive<int>(0);
final Reactive<String> title = Reactive<String>('Flutter');
final Reactive<bool> isDark = Reactive<bool>(false);
Reading Values #
Use .value to access the current value.
print(counter.value);
Updating Values #
Update the value using .value.
counter.value = counter.value + 1;
isDark.value = true;
Silent Updates #
Use setSilent() to update a value without notifying listeners.
counter.setSilent(100);
Watch Widget #
Watch automatically rebuilds whenever a reactive value used inside the builder changes.
No dependency list is required.
Basic Example #
Watch(
builder: () {
return Text('${counter.value}');
},
)
Multiple Reactive Dependencies #
Watch(
builder: () {
return Column(
children: [
Text('${counter.value}'),
Text(title.value),
Switch(
value: isDark.value,
onChanged: (value) {
isDark.value = value;
},
),
],
);
},
)
Conditional Tracking #
Dependencies are tracked automatically based on what is accessed during build.
Watch(
builder: () {
return isDark.value
? Text('Dark Mode')
: Text('Light Mode');
},
)
Only the reactive values used in the active branch are subscribed.
Dependency Injection #
ReactiveInjector is a lightweight service locator.
Supports:
- Singleton registration
- Transient registration
- Dependency lookup
- Reset
- Unregister
- Clear all
Register Singleton #
Singletons reuse the same instance.
ReactiveInjector.singleton<ApiService>(
() => ApiService(),
);
Retrieve the dependency:
final ApiService api = ReactiveInjector.find<ApiService>();
Register Transient #
Transient dependencies create a new instance every time.
ReactiveInjector.transient<UserRepository>(
() => UserRepository(),
);
Check Registration #
final bool exists = ReactiveInjector.isRegistered<ApiService>();
Reset Singleton #
Clears the cached singleton instance.
ReactiveInjector.reset<ApiService>();
Unregister Dependency #
ReactiveInjector.unregister<ApiService>();
Clear All Dependencies #
ReactiveInjector.clear();
Page-Based Pagination #
ReactivePagination<T> helps manage paginated APIs using page numbers.
Create Pagination Controller #
final ReactivePagination<User> pagination = ReactivePagination<User>(
perPage: 20,
fetcher: (page, perPage) async {
return api.fetchUsers(page, perPage);
},
);
Initialize Pagination #
await pagination.init();
Refresh Pagination #
await pagination.refresh();
Load More #
await pagination.fetchMore();
Access Pagination State #
pagination.items
pagination.isLoading
pagination.isMoreLoading
pagination.hasMore
pagination.error
pagination.totalFetched
pagination.isEmpty
Watch Pagination State #
Watch(
builder: () {
if (pagination.isLoading) {
return const CircularProgressIndicator();
}
return ListView.builder(
itemCount: pagination.items.length,
itemBuilder: (context, index) {
final user = pagination.items[index];
return ListTile(
title: Text(user.name),
);
},
);
},
)
Cursor-Based Pagination #
ReactiveCursorPagination<T, C> supports APIs that use cursors.
C represents the cursor type.
Examples:
StringintDateTimeDocumentSnapshot(Firebase Firestore)- Custom cursor model
Create Cursor Pagination #
final ReactiveCursorPagination<User, String> pagination =
ReactiveCursorPagination<User, String>(
perPage: 20,
fetcher: (perPage, cursor) async {
return api.fetchUsers(perPage, cursor);
},
);
PaginationResult #
Cursor pagination fetchers return PaginationResult<T, C>.
PaginationResult<User, String>(
items: users,
nextCursor: nextCursor,
)
Cursor Pagination State #
pagination.items
pagination.cursor
pagination.isLoading
pagination.isMoreLoading
pagination.hasMore
pagination.error
pagination.totalFetched
pagination.isEmpty
Example App #
import 'package:flutter/material.dart';
import 'package:reactive_flutter/reactive_flutter.dart';
final Reactive<int> counter = Reactive<int>(0);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Reactive State'),
),
body: Center(
child: Watch(
builder: () {
return Text(
'${counter.value}',
style: const TextStyle(fontSize: 40),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counter.value++;
},
child: const Icon(Icons.add),
),
),
);
}
}
API Overview #
Reactive #
| Function | Description |
|---|---|
value |
Get or update the reactive value |
setSilent() |
Update value without notifying listeners |
toString() |
Returns debug string |
Watch #
| Property | Description |
|---|---|
builder |
Widget builder automatically tracked |
ReactiveInjector #
| Function | Description |
|---|---|
singleton() |
Register singleton dependency |
transient() |
Register transient dependency |
find() |
Resolve dependency |
isRegistered() |
Check if dependency exists |
reset() |
Reset singleton instance |
unregister() |
Remove dependency |
clear() |
Remove all dependencies |
ReactivePagination #
| Function | Description |
|---|---|
init() |
Load first page |
refresh() |
Reload from beginning |
fetchMore() |
Load next page |
ReactiveCursorPagination #
| Function | Description |
|---|---|
init() |
Load first page |
refresh() |
Reload from beginning |
fetchMore() |
Load next cursor page |
Why reactive_flutter? #
reactive_flutter focuses on simplicity.
Unlike larger state management solutions, it provides:
- Minimal API surface
- Automatic dependency tracking
- No boilerplate
- No generators
- No annotations
- Lightweight architecture
- Easy integration into existing apps
Perfect for:
- Small apps
- Medium apps
- Prototypes
- Utility apps
- Feature modules
- Developers who prefer minimalism
Performance #
reactive_flutter is designed to stay lightweight and fast.
Why it performs well #
- No reflection
- No code generation
- No runtime dependency graph building
- Fine-grained rebuild tracking
- Only widgets that access a reactive value rebuild
- Conditional dependencies are handled automatically
Architecture #
Reactive<T>
↓
ReactiveTracker
↓
Watch Widget
↓
Automatic Rebuild
How it works #
Watchstarts dependency tracking.- Any accessed
Reactive.valueregisters itself. Watchsubscribes only to accessed reactives.- When a reactive changes, only subscribed widgets rebuild.
Comparison #
| Feature | reactive_flutter | GetX | Riverpod | Provider |
|---|---|---|---|---|
| Auto tracking | ✅ | ⚠️ Partial | ❌ | ❌ |
| Code generation | ❌ | ❌ | ⚠️ Optional | ❌ |
| Boilerplate | Very Low | Low | Medium | Medium |
| Dependency injection | ✅ | ✅ | ❌ | ❌ |
| Pagination helpers | ✅ | ❌ | ❌ | ❌ |
| Learning curve | Easy | Easy | Medium | Easy |
| Lightweight | ✅ | ⚠️ | ⚠️ | ✅ |
Advanced Reactive Example #
final Reactive<List<String>> todos = Reactive<List<String>>([]);
void addTodo(String value) {
todos.value = [...todos.value, value];
}
void removeTodo(String value) {
todos.value = todos.value.where((e) => e != value).toList();
}
Nested Watch Example #
Watch(
builder: () {
return Column(
children: [
Watch(
builder: () {
return Text(counter.value.toString());
},
),
Watch(
builder: () {
return Text(title.value);
},
),
],
);
},
)
Scroll Pagination Example #
class UsersPage extends StatefulWidget {
const UsersPage({super.key});
@override
State<UsersPage> createState() => _UsersPageState();
}
class _UsersPageState extends State<UsersPage> {
final ScrollController _controller = ScrollController();
final ReactivePagination<User> pagination = ReactivePagination<User>(
perPage: 20,
fetcher: (page, limit) async {
return api.fetchUsers(page, limit);
},
);
@override
void initState() {
super.initState();
pagination.init();
_controller.addListener(() {
if (_controller.position.pixels >=
_controller.position.maxScrollExtent - 200) {
pagination.fetchMore();
}
});
}
@override
Widget build(BuildContext context) {
return Watch(
builder: () {
return ListView.builder(
controller: _controller,
itemCount: pagination.items.length,
itemBuilder: (context, index) {
final user = pagination.items[index];
return ListTile(
title: Text(user.name),
);
},
);
},
);
}
}
Unit Testing Example #
void main() {
test('Reactive value updates correctly', () {
final Reactive<int> counter = Reactive<int>(0);
counter.value = 5;
expect(counter.value, 5);
});
}
Dependency Injection Example #
class ApiService {
String get title => 'Reactive State';
}
void setupDependencies() {
ReactiveInjector.singleton<ApiService>(
() => ApiService(),
);
}
final ApiService api = ReactiveInjector.find<ApiService>();
FAQ #
Does this use code generation? #
No. reactive_flutter works without generators or build_runner.
Does Watch rebuild the whole app? #
No.
Only widgets subscribed to changed reactive values rebuild.
Can I use it with existing architectures? #
Yes.
You can integrate it with:
- Clean Architecture
- MVVM
- MVC
- Feature-first architecture
- Existing Provider/Riverpod/GetX apps
Does it support async state? #
Yes.
You can store Futures, async results, pagination state, and API responses inside reactive values.
Is it production ready? #
Yes.
The library is designed to be lightweight, predictable, and suitable for production applications.
Roadmap #
- ❌ Computed reactive values
- ❌ Reactive collections
- ❌ DevTools integration
- ❌ Async reactive helpers
- ❌ Stream bindings
- ❌ Form utilities
- ❌ Persistent storage helpers
- ❌ Flutter Web optimizations
Contributing #
Contributions are welcome.
Setup #
git clone <repository>
cd reactive_flutter
flutter pub get
Run Tests #
flutter test
Format Code #
dart format .
License #
MIT License