loupe 0.0.1
loupe: ^0.0.1 copied to clipboard
A lightweight non invasive reactive system for Dart
Loupe #
A minimal, dependency-free reactive state management library for Dart.
Loupe provides a simple observation system that lets you watch objects for changes and get notified when they occur. It's designed to be lightweight, with no dependencies and minimal overhead.
Features #
- Zero dependencies - Pure Dart, no external packages required
- Lightweight - Minimal memory footprint, uses
Expandofor efficient object tracking - Simple API - Just
loupe.watch(),loupe.watchMany(), andloupe.notifyChanges() - No magic - Explicit change notification, no proxies or code generation
Installation #
Add to your pubspec.yaml:
dependencies:
loupe:
git:
url: https://github.com/your-repo/loupe.git
ref: main
Or if published to pub.dev:
dependencies:
loupe: ^1.0.0
Usage #
Recommended: Use the loupe. prefix for all functions to avoid naming conflicts.
import 'package:loupe/loupe.dart' as loupe;
Basic Usage #
import 'package:loupe/loupe.dart' as loupe;
// Create an observable object
final counter = Counter();
// Watch for changes
final subscription = loupe.watch(counter, () {
print('Counter changed!');
});
// Notify listeners when the object changes
counter.increment();
loupe.notifyChanges(counter); // Triggers the callback
// Clean up when done
subscription.cancel();
Watching Multiple Objects #
import 'package:loupe/loupe.dart' as loupe;
final user = User();
final settings = Settings();
final subscription = loupe.watchMany([user, settings], () {
print('User or settings changed!');
});
// Later...
user.updateName('Alice');
loupe.notifyChanges(user); // Triggers callback
settings.updateTheme('dark');
loupe.notifyChanges(settings); // Also triggers callback
subscription.cancel();
Immediate Notification #
import 'package:loupe/loupe.dart' as loupe;
final data = Data();
// Get immediate callback on subscription
final subscription = loupe.watch(data, () {
print('Data changed!');
}, immediate: true); // Callback runs immediately
subscription.cancel();
Merging Subscriptions #
import 'package:loupe/loupe.dart' as loupe;
final sub1 = loupe.watch(obj1, () => print('obj1 changed'));
final sub2 = loupe.watch(obj2, () => print('obj2 changed'));
// Combine into one subscription
final merged = sub1.merge(sub2);
// Later, cancel both with one call
merged.cancel();
API Reference #
loupe.watch(Object obj, Function() onChange, {bool immediate = false}) #
Watches a single object for changes.
obj- The object to watchonChange- Callback invoked when the object changesimmediate- If true, callsonChangeimmediately on subscription
Returns a Subscription that can be cancelled.
loupe.watchMany(Iterable<Object> objs, Function() onChange, {bool immediate = false}) #
Watches multiple objects for changes.
objs- The objects to watchonChange- Callback invoked when any watched object changesimmediate- If true, callsonChangeimmediately on subscription
Returns a Subscription that can be cancelled.
loupe.notifyChanges(Object obj) #
Notifies all listeners that an object has changed.
obj- The object that changed
Subscription #
A subscription that can be cancelled.
cancel()- Cancels the subscriptionmerge(Subscription other)- Returns a new subscription that cancels both when cancelled
Important Notes #
- Object Identity: Loupe uses object identity (reference equality) to track objects. Primitive types (int, String, bool, etc.) that are not boxed in objects will not work correctly. Always use reference types.
- Manual Notification: You must call
notifyChanges(obj)explicitly when an object changes. Loupe does not automatically detect changes. - Memory Management: Always cancel subscriptions when they are no longer needed to prevent memory leaks.
Example: Simple State Management #
import 'package:loupe/loupe.dart' as loupe;
class Counter {
int _count = 0;
int get count => _count;
void increment() {
_count++;
loupe.notifyChanges(this);
}
void decrement() {
_count--;
loupe.notifyChanges(this);
}
}
void main() {
final counter = Counter();
final subscription = loupe.watch(counter, () {
print('Counter is now: ${counter.count}');
});
counter.increment(); // Prints: Counter is now: 1
counter.increment(); // Prints: Counter is now: 2
counter.decrement(); // Prints: Counter is now: 1
subscription.cancel();
}
License #
MIT License.