ScopedObserverMixin mixin

Mixin for plain Dart classes (controllers, stores, services) that own reactive resources and want them disposed with a single call — the pure-Dart counterpart of ObserverStateMixin, with no State, no BuildContext, and no package:flutter import.

Everything created inside scoped (a Computed, an effect(), a worker) is registered in this object's internal ReactiveScope; any other Disposer-shaped resource can be registered via autoDispose — the same name and shape as ObserverStateMixin.autoDispose, kept deliberately symmetric. Call disposeScope from your own teardown method (a close(), dispose(), onClose(), ...) to release all of it at once, in reverse registration (LIFO) order.

scoped(fn) was chosen (over an initState-style lifecycle hook) because plain Dart classes have no framework-managed lifecycle to hang such a hook on — a regular method that wraps any code block composes with constructors, late final field initializers, and ordinary methods alike, which is exactly how controllers create resources in practice.

The internal scope is created lazily, on the first use of any member of this mixin. If that first use happens to run inside another scope's run(), this scope becomes its child (see ReactiveScope's nesting note); typically controllers are constructed outside any run() and no nesting occurs.

Mixin para classes Dart puras (controllers, stores, services) que possuem recursos reativos e querem descartá-los com uma única chamada — a contraparte em Dart puro do ObserverStateMixin, sem State, sem BuildContext e sem import de package:flutter.

Tudo que for criado dentro de scoped (um Computed, um effect(), um worker) é registrado no ReactiveScope interno deste objeto; qualquer outro recurso com forma de Disposer pode ser registrado via autoDispose — mesmo nome e forma de ObserverStateMixin.autoDispose, mantidos deliberadamente simétricos. Chame disposeScope no seu próprio método de teardown (um close(), dispose(), onClose(), ...) para liberar tudo de uma vez, em ordem inversa de registro (LIFO).

scoped(fn) foi a escolha (em vez de um gancho de ciclo de vida ao estilo initState) porque classes Dart puras não têm um ciclo de vida gerenciado por framework onde pendurar esse gancho — um método comum que envolve qualquer bloco de código compõe igualmente com construtores, inicializadores de campo late final e métodos comuns, que é exatamente como controllers criam recursos na prática.

O escopo interno é criado preguiçosamente, no primeiro uso de qualquer membro deste mixin. Se esse primeiro uso acontecer dentro do run() de outro escopo, este escopo vira filho dele (ver a nota de aninhamento de ReactiveScope); tipicamente controllers são construídos fora de qualquer run() e nenhum aninhamento ocorre.

Example / Exemplo:

class CounterController with ScopedObserverMixin {
  final a = Observable<int>(1);
  final b = Observable<int>(2);

  late final Computed<int> total =
      scoped(() => Computed(() => a.value + b.value));

  CounterController() {
    scoped(() {
      effect(() => print('total: ${total.value}'));
      ever(a, (_) => save());
    });
  }

  void close() => disposeScope();
}

Properties

hashCode int
The hash code for this object.
no setterinherited
isScopeDisposed bool
Whether disposeScope has already been called.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
scope ReactiveScope
The internal ReactiveScope owning every resource this mixin registered. Exposed for advanced composition (e.g. handing it to a child object, or manual inspection); most code only needs scoped, autoDispose and disposeScope.
latefinal

Methods

autoDispose(Disposer disposer) → void
Registers disposer to be called by disposeScope — same shape and intent as ObserverStateMixin.autoDispose, for resources the scope does not capture on its own (a subscription.cancel, an observable.close, ...). Sugar for scope.add(disposer), including its already-disposed behavior (immediate disposal + warning, throw under strictMode).
disposeScope() → void
Disposes everything registered so far, in reverse registration (LIFO) order. Idempotent. Call it from your class's own teardown method.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
scoped<R>(R fn()) → R
Runs fn inside this object's scope and returns its result: every Computed/effect()/worker created inside fn is disposed by disposeScope. Sugar for scope.run(fn).
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited