AsyncSignal#
class & function |
Package: package:signals_core
Class: AsyncSignal#
A highly powerful Signal specifically designed for manual, imperative asynchronous state management.
Unlike declarative reactive signals like futureSignal or streamSignal
(which automatically wrap and listen
to an existing Future or Stream), AsyncSignal
gives you full manual/imperative control over pushing
async states (AsyncState.loading, AsyncState.data, and
AsyncState.error) into the reactive graph.
This is the perfect state primitive for building custom repositories, handling manual user action triggers (e.g., submitting a registration form, calling an API on button click), or bridging low-level callback-based APIs into reactive states.
1. Imperative State Mutations#
You can update the state of the signal directly using specialized mutation helpers:
setLoading()puts the signal into a cleanAsyncLoadingstate.setValue(T data)pushes a newAsyncDatastate containing the data.-
setError(Object error, [StackTrace? stackTrace])transitions the signal to anAsyncErrorstate.
final authState = asyncSignal<User>(AsyncState.loading());
Future<void> login(String email, String password) async {
try {
authState.setLoading(); // Set UI to loading state
final user = await authApi.signIn(email, password);
authState.setValue(user); // Push success data
} catch (err, stack) {
authState.setError(err, stack); // Push error state
}
}
2. Awaiting Async Completion via .future#
An outstanding capability of AsyncSignal is its built-in .future getter. Any part of your code can await
this future. It returns a standard Future that resolves when the signal next receives a data value,
or throws if the signal next receives an error state.
final loginSignal = asyncSignal<User>(AsyncState.loading());
// Task A: Start background operation
Future.delayed(Duration(seconds: 2), () {
loginSignal.setValue(User(name: 'Charlie'));
});
// Task B: Wait for the signal to resolve!
final user = await loginSignal.future; // Suspends execution until Task A completes!
print(user.name); // 'Charlie'
3. Rendering in Flutter using Watch and AsyncState Pattern matching#
In your Flutter widgets, you can seamlessly watch the signal and use Dart's native pattern matching on AsyncState to render different widgets corresponding to the current asynchronous lifecycle:
Widget build(BuildContext context) {
final state = authState.watch(context);
return state.map(
data: (user) => HomeScreen(user: user),
error: (error, stackTrace) => ErrorWidget(error),
loading: () => const CircularProgressIndicator(),
);
}
4. Bridging callback/event-driven systems via EventSink#
AsyncSignal implements Dart's standard EventSink interface. This allows it to act directly as an event sink
for streams, websockets, or callback listeners:
final messageLog = asyncSignal<String>(AsyncState.loading());
final chatStream = webSocket.stream.map((event) => event.toString());
// Automatically push all incoming messages and errors from the stream into the signal:
chatStream.listen(
(msg) => messageLog.add(msg),
onError: (err) => messageLog.addError(err),
onDone: () => messageLog.close(),
);
AsyncSignal when you need manual, callback-driven, or button-press-triggered state mutations.
For auto-triggering, declarative, or read-only asynchronous data dependencies (like pulling data when an ID changes),
favor futureSignal or computedAsync instead.
Members of AsyncSignal#
| Member | Type | Signature | Description |
|---|---|---|---|
| AsyncSignal | constructor |
dart AsyncSignal(super.value, {super.options}) |
A Signal that stores value in AsyncState |
| future | method |
dart Future |
The future of the signal completer |
| isCompleted | method |
dart bool isCompleted |
Returns true if the signal is completed an error or data |
| setError | method |
dart void setError(Object error, [StackTrace? stackTrace]) |
Set the error with optional stackTrace to AsyncError |
| setValue | method |
dart void setValue(T value) |
Set the value to AsyncData |
| setLoading | method |
dart void setLoading([AsyncState |
Set the loading state to AsyncLoading |
| reset | method |
dart void reset([AsyncState |
Reset the signal to the initial value |
| init | method |
dart void init() |
Initialize the signal |
| reload | method |
dart Future |
Reload the future |
| refresh | method |
dart Future |
Refresh the future |
| value | method |
dart AsyncState |
|
| requireValue | method |
dart T requireValue |
Returns the value of the signal |
Function: asyncSignal#
AsyncSignal<T> asyncSignal(AsyncState<T> value, {AsyncSignalOptions<T>? options, @Deprecated('Use options: AsyncSignalOptions(name: ...) instead') String? debugLabel, @Deprecated('Use options: AsyncSignalOptions(autoDispose: ...) instead') bool? autoDispose})
Helper function to create an AsyncSignal initialized with an AsyncState.
Example#
// Create an AsyncSignal initialized to a loading state
final counter = asyncSignal<int>(AsyncState.loading());
// Create an AsyncSignal initialized with initial data
final status = asyncSignal<String>(AsyncState.data('Active'));
References#
The AsyncSignal type is referenced and used in the following pages:
- SignalsMixin (signals_flutter/mixins)
- AsyncState (signals_flutter/async)
- AsyncSignal (signals_flutter/async)
- signals_flutter
- AsyncState (signals_core/async)
- AsyncSignal (signals_core/async)
- signals_core
- SignalsMixin (signals/mixins)
- AsyncState (signals/async)
- AsyncSignal (signals/async)
- signals
- useAsyncSignal (signals_hooks/hooks)