mutate<R> method
Runs action, then notifies every listener that state changed.
Supports both synchronous actions and asynchronous actions (returning a Future). For asynchronous actions, listeners are notified once the returned Future completes.
Returns the result of action.
Optionally pass label to override the action name for Orbit.observe middleware
and debug logging — e.g. mutate(() => count++) (automatically uses 'increment').
If omitted, label is automatically inferred from the calling method name.
If you also override snapshot, Orbit logs exactly which
fields changed.
Implementation
@protected
R mutate<R>(R Function() action, {String? label}) {
final tracking = Orbit.debugLogging || Orbit._hasObservers;
// In non-release builds _notify must always run so that postEvent fires
// and the VS Code / DevTools extension receives live state updates —
// even when debugLogging is off and no observers are registered.
final notify = tracking || !kReleaseMode;
// Snapshots/label inference are gated on `notify`, not the narrower
// `tracking`: postEvent (which powers the VS Code/DevTools extension)
// fires whenever `notify` is true and reads `mutation.after` directly,
// so it must always have a real snapshot to read — gating on `tracking`
// alone left it silently empty whenever debugLogging was off and no
// observers were registered, even with the extension attached.
final inferredLabel = notify ? _inferLabel(label) : label;
final before = notify ? _safeSnapshot() : null;
try {
final result = action();
if (result is Future) {
var hasError = false;
Object? asyncError;
StackTrace? asyncStack;
return (result as Future)
.catchError((Object error, StackTrace stackTrace) {
hasError = true;
asyncError = error;
asyncStack = stackTrace;
throw error;
}).whenComplete(() {
_dispatchNotify();
if (notify) {
Orbit._notify(
this,
OrbitMutation(
store: this,
action: inferredLabel,
timestamp: DateTime.now(),
listenerCount: _listenerCount,
before: before,
after: _safeSnapshot(),
error: hasError ? asyncError : null,
errorStackTrace: hasError ? asyncStack : null,
),
);
}
}) as R;
}
_dispatchNotify();
if (notify) {
Orbit._notify(
this,
OrbitMutation(
store: this,
action: inferredLabel,
timestamp: DateTime.now(),
listenerCount: _listenerCount,
before: before,
after: _safeSnapshot(),
),
);
}
return result;
} catch (error, stackTrace) {
_dispatchNotify();
if (notify) {
Orbit._notify(
this,
OrbitMutation(
store: this,
action: inferredLabel,
timestamp: DateTime.now(),
listenerCount: _listenerCount,
before: before,
after: _safeSnapshot(),
error: error,
errorStackTrace: stackTrace,
),
);
}
rethrow;
}
}