LogoSignals.dart
Copy Markdown
rodydavis/signals.dart 999999

Type: FutureSignal

API reference and details for FutureSignal from signals.dart.

FutureSignal#

Kind: class & function  |  Package: package:signals_core

Class: FutureSignal#

Future signals wrap a standard asynchronous Future and bridge it into the reactive state framework, exposing its lifecycle and value as a reactive AsyncState.

You can construct a future signal via the helper function futureSignal or by calling the .toSignal() extension method on any standard Future.

1. Basic Async Fetching#

final s = futureSignal(() async {
  final data = await fetchUserData(123);
  return data;
});

Or via the extension:

final s = fetchUserData(123).toSignal();

2. Consuming and Pattern Matching AsyncState#

Reading .value on a FutureSignal returns an AsyncState object. You can safely pattern-match or map this state to reactively build your user interface or perform side-effects:

effect(() {
  s.value.map(
    data: (user) => print('User fetched successfully: ${user.name}'),
    error: (err, stack) => print('Failed to fetch user: $err'),
    loading: () => print('Loading user...'),
  );
});

3. Reset, Refresh, and Reload#

  • reset(): Reverts the signal back to its initial/loading state.
  • refresh(): Triggers a new evaluation of the future while maintaining the current data in the meantime (sets isLoading to true but does not discard existing data/error).
  • reload(): Discards current state, sets the signal to AsyncLoading, and executes a fresh evaluation of the future.
final s = futureSignal(() => fetchConfig());
s.refresh(); // Triggers reload under the hood

4. Reactive Dependencies#

Any reactive signals read synchronously inside the future callback are registered as dependencies. When they mutate, the future signal automatically invalidates and schedules a fresh fetch.

final userId = signal(123);
final userProfile = futureSignal(() async {
  // Subscribes to userId! Mutating userId automatically re-runs this future.
  final currentId = userId.value;
  return fetchUserProfile(currentId);
});
If you need to track dependencies across an asynchronous gap (i.e. reading a signal's value after an await), pass them explicitly in the dependencies list inside AsyncSignalOptions or the constructor to guarantee they are properly subscribed.

Members of FutureSignal#

Member Type Signature Description
FutureSignal constructor dart FutureSignal(Future Function() fn, {AsyncSignalOptions ? options, @Deprecated('Use options: AsyncSignalOptions(initialValue: ...) instead') T? initialValue, @Deprecated('Use options: AsyncSignalOptions(dependencies: ...) instead') List<ReadonlySignal >? dependencies, @Deprecated('Use options: AsyncSignalOptions(lazy: ...) instead') bool? lazy, @Deprecated('Use options: AsyncSignalOptions(autoDispose: ...) instead') bool? autoDispose, @Deprecated('Use options: AsyncSignalOptions(name: ...) instead') String? debugLabel}) Future signals can be created by extension or method.
dependencies field dart List<ReadonlySignal> dependencies List of dependencies to recompute the future
dispose method dart void dispose()
reset method dart void reset([AsyncState? value])
init method dart void init()
value method dart AsyncState value
reload method dart Future reload()
refresh method dart Future refresh()

Function: futureSignal#

FutureSignal<T> futureSignal(Future<T> Function() fn, {AsyncSignalOptions<T>? options, @Deprecated('Use options: AsyncSignalOptions(initialValue: ...) instead') T? initialValue, @Deprecated('Use options: AsyncSignalOptions(dependencies: ...) instead') List<ReadonlySignal<dynamic>>? dependencies, @Deprecated('Use options: AsyncSignalOptions(lazy: ...) instead') bool? lazy, @Deprecated('Use options: AsyncSignalOptions(autoDispose: ...) instead') bool? autoDispose, @Deprecated('Use options: AsyncSignalOptions(name: ...) instead') String? debugLabel})

Future signals can be created by extension or method.

futureSignal#

final s = futureSignal(() async => 1);

toSignal()#

final s = Future(() => 1).toSignal();

.value, .peek()#

Returns AsyncState for the value and can handle the various states.

The value getter returns the value of the future if it completed successfully.

.peek() can also be used to not subscribe in an effect

final s = futureSignal(() => Future(() => 1));
final value = s.value.value; // 1 or null

.reset()#

The reset method resets the future to its initial state to recall on the next evaluation.

final s = futureSignal(() => Future(() => 1));
s.reset();

.refresh()#

Refresh the future value by setting isLoading to true, but maintain the current state (AsyncData, AsyncLoading, AsyncError).

final s = futureSignal(() => Future(() => 1));
s.refresh();
print(s.value.isLoading); // true

.reload()#

Reload the future value by setting the state to AsyncLoading and pass in the value or error as data.

final s = futureSignal(() => Future(() => 1));
s.reload();
print(s.value is AsyncLoading); // true

Dependencies#

By default the callback will be called once and the future will be cached unless a signal is read in the callback.

final count = signal(0);
final s = futureSignal(() async => count.value);

await s.future; // 0
count.value = 1;
await s.future; // 1

If there are signals that need to be tracked across an async gap then use the dependencies when creating the futureSignal to reset every time any signal in the dependency array changes.

final count = signal(0);
final s = futureSignal(
    () async => count.value,
    dependencies: [count],
);
s.value; // state with count 0
count.value = 1; // resets the future
s.value; // state with count 1

References#

The FutureSignal type is referenced and used in the following pages: