Reactions
The MobX triad is completed when we add Reactions into the mix. Having reactions is what triggers the reactivity in the system. A reaction implicitly tracks all the observables which are being used and then re-executes its logic whenever the depending-observables change.
Technically, a computed is also a reaction, aka Derivation, as it depends on
other observables or computeds. The only difference between a regular Reaction
and Computed
is that the former does not produce any value. Computeds are
mostly read-only observables that derive their value from other observables.
Reactions, or Derivations come in few flavors: autorun
, reaction
, when
and
of course the Flutter Widget: Observer
. All of these variations take a
function that is tracked for any observables. When the tracked observables
change, the function is re-executed. This simple behavior is the defining
characteristic of a reaction. Note that there is no explicit subscription or
wiring needed. Reactions also return a disposer-function (ReactionDisposer
)
that can be invoked to pre-maturely dispose a reaction.
autorun​
ReactionDisposer autorun(Function(Reaction) fn)
​
Runs the reaction immediately and also on any change in the observables used
inside fn
.
import 'package:mobx/mobx.dart';
final greeting = Observable('Hello World');
final dispose = autorun((_){
print(greeting.value);
});
greeting.value = 'Hello MobX';
// Done with the autorun()
dispose();
// Prints:
// Hello World
// Hello MobX
reaction​
ReactionDisposer reaction<T>(T Function(Reaction) fn, void Function(T) effect)
​
Monitors the observables used inside the fn()
tracking function and runs the
effect()
when the tracking function returns a different value. Only the
observables inside fn()
are tracked.
import 'package:mobx/mobx.dart';
final greeting = Observable('Hello World');
final dispose = reaction((_) => greeting.value, (msg) => print(msg));
greeting.value = 'Hello MobX'; // Cause a change
// Done with the reaction()
dispose();
// Prints:
// Hello MobX
when​
ReactionDisposer when(bool Function(Reaction) predicate, void Function() effect)
​
Monitors the observables used inside predicate()
and runs the effect()
when it returns true
. After the effect()
is run, when
automatically
disposes itself. So you can think of when as a one-time reaction
. You can
also dispose when()
pre-maturely.
import 'package:mobx/mobx.dart';
final greeting = Observable('Hello World');
final dispose = when((_) => greeting.value == 'Hello MobX', () => print('Someone greeted MobX'));
greeting.value = 'Hello MobX'; // Causes a change, runs effect and disposes
// Prints:
// Someone greeted MobX
asyncWhen​
Future<void> asyncWhen(bool Function(Reaction) predicate)
​
Similar to when
but returns a Future
, which is fulfilled when the
predicate()
returns true. This is a convenient way of waiting for the
predicate()
to turn true
.
final completed = Observable(false);
void waitForCompletion() async {
await asyncWhen(() => completed.value == true);
print('Completed');
}