all_observer 1.1.0 copy "all_observer: ^1.1.0" to clipboard
all_observer: ^1.1.0 copied to clipboard

Lightweight reactive state management for Flutter with zero external dependencies: observable values plus an auto-tracking Observer widget.

1.1.0 #

Additive release — no breaking changes, no new external dependencies.

Async:

  • ObservableFuture<T>: an Observable<AsyncState<T>> that runs a Future<T> Function() and tracks its loading/data/error lifecycle. Auto-runs by default (autoStart: true) or via run()/refresh(). Race-safe: a generation counter discards a stale run()'s result if a newer run() started before it resolved, and discards any result that arrives after close().
  • AsyncState<T> sealed class: AsyncLoading<T> (with previousData for stale-while-loading UIs), AsyncData<T>, AsyncError<T>; when/maybeWhen, isLoading/hasData/hasError/valueOrNull, content-based ==/hashCode.

Computed:

  • equals named parameter on Computed's constructor, mirroring Observable's, for custom change-detection (e.g. floating-point tolerance) on the recomputed value.
  • Diamond-glitch mitigation: inside an active Observable.batch(), a Computed's recompute is deferred (to the next value read, or to end-of-batch, whichever comes first) instead of running eagerly per upstream notification — so a diamond-shaped dependency graph recomputes at most once per batch, with every dependency already at its final value. Outside batch, the previous eager-recompute-per-notification behavior is unchanged and documented as a known limitation.

Widgets:

  • Observer.withChild named constructor: rebuilds only the part of the subtree the builder itself constructs, reusing a static child widget across rebuilds instead of reconstructing it — for expensive widgets that don't depend on any observable.

Observable:

  • Observable.setValue(T newValue): equivalent to value = newValue, usable as a tear-off (e.g. directly as an onChanged callback) and the unambiguous way to assign null to an Observable<T?> (unlike call(null), which reads instead of assigns).
  • Observable<T>.select<R>(R Function(T value) selector, {String? name}) extension: sugar over Computed(() => selector(value), name: name) for a narrower, memoized derived value. Caller owns and must close() the returned Computed.

Performance:

  • ListenerRegistry now backed by a LinkedHashSet<VoidCallback> instead of a List, making add/remove/contains O(1) instead of O(n), while preserving insertion order and native deduplication. See benchmark/listener_registry_benchmark.dart.

Other:

  • example/ reworked into a multi-page app (bottom navigation) with five focused demos: counter + Computed, debounced search, ObservableFuture async states, Observable.batch form saving, and Observer/ValueListenableBuilder interop — each in its own file under example/lib/demos/.
  • README (EN/PT-BR): new "Migrating from other reactive state solutions" section (concept-based equivalence table) and a "Known limitations" section (diamond glitch outside batch, Computed staying active after first read until close(), single-isolate confinement).

1.0.0 #

Initial release.

Core:

  • Observable<T> reactive value, plus ObservableInt, ObservableDouble, ObservableBool, ObservableString.
  • .obs extension for creating observables from literals and collections.
  • ObservableList, ObservableMap, ObservableSet reactive collections; reading any member tracks it, mutating any member notifies at most once per call — bulk operations (addAll, removeWhere, retainWhere, insertAll, clear, sort, shuffle) never notify once per element, and no-op mutations (adding a duplicate Set element, removeWhere that removes nothing, map[k]=v with an identical value, clear() on an already-empty collection) don't notify at all.
  • Observer widget with automatic, stack-based dependency tracking and safe rebuild scheduling (no "defunct element" crashes).
  • ObserverValue for self-contained local reactive state.
  • Computed<T>: lazy, memoized derived values reusing the same dependency tracker as Observer; supports dynamic/conditional dependencies; only notifies when the derived value actually changes; close() unsubscribes from all current dependencies.
  • Observable.batch(() { ... }): coalesces multiple writes inside the callback into a single notification per changed observable/collection for manual (listen/ever) subscribers, with nested-batch support.
  • equals parameter on the Observable<T> constructor, for custom change-detection (e.g. floating-point tolerance) instead of ==.
  • listen/ObservableSubscription, stream-free manual subscriptions.
  • Workers: ever, once, debounce, interval, plus Worker/Workers.

Robustness:

  • An exception thrown inside one ever/listen callback does not stop other listeners of the same observable from running; it is reported via FlutterError.reportError (library: 'all_observer') instead of being swallowed or propagating.
  • A synchronous update cycle (a listener of A writing to B, whose listener writes back to A) stops after a bounded notification depth with a descriptive FlutterError, instead of crashing with a raw stack overflow.
  • Observer: if the builder throws during a tracked build, dependency disposers accumulated up to that point are still assigned, so the next build/unmount does not leak or double-register listeners.
  • The "write during build" warning covers both Observable.value = and reactive-collection mutations, and ObserverConfig.strictMode turns this case into a thrown ObserverError as well as the "empty Observer" case.
  • listen()/close() on an already-close()d Observable/collection returns an inert (already-canceled) subscription instead of silently registering a listener that can never fire; a mutation attempted on a closed collection is a full no-op (the underlying data is left untouched), and double-close() is safe.
  • Documented, in Observable's dartdoc, that writing to an observable from a different isolate does not work (no cross-isolate synchronization is attempted).

Other:

  • Debug-only, ANSI-colored logging via ObserverConfig and non-fatal misuse warnings (with optional strictMode).
  • Zero external dependencies; full ValueListenable interoperability.

See AUDIT_REPORT.md at the repository root for the full item-by-item performance/robustness audit this release was validated against.

3
likes
0
points
1.12k
downloads

Publisher

verified publisheropensource.tatamemaster.com.br

Weekly Downloads

Lightweight reactive state management for Flutter with zero external dependencies: observable values plus an auto-tracking Observer widget.

Repository (GitHub)
View/report issues

Topics

#state-management #reactive #observable

License

unknown (license)

Dependencies

flutter

More

Packages that depend on all_observer