loupe 0.0.1 copy "loupe: ^0.0.1" to clipboard
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 Expando for efficient object tracking
  • Simple API - Just loupe.watch(), loupe.watchMany(), and loupe.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 watch
  • onChange - Callback invoked when the object changes
  • immediate - If true, calls onChange immediately 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 watch
  • onChange - Callback invoked when any watched object changes
  • immediate - If true, calls onChange immediately 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 subscription
  • merge(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.

0
likes
140
points
98
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A lightweight non invasive reactive system for Dart

Repository

License

BSD-3-Clause (license)

More

Packages that depend on loupe