Saltearse al contenido

UseAsyncState

Esta página aún no está disponible en tu idioma.

UseAsyncState is a hook that allows to declare state variables and manipulate its value asynchronously, which in turn notifies about its changes to listeners.

Syntax

UseAsyncState<T>(
Future<T> asyncFunction(),
T initialValue,
{ String? debugLabel },
);
// UseAsyncState with arguments
UseAsyncState<T, A>.withArg(
Future<T> asyncFunction(A arg),
T initialValue,
{ String? debugLabel },
);

UseAsyncState accepts these parameters:

  • asyncFunction : A function that returns a Future<T> to update the state asynchronously. This function is called by the resolve method and sets the value property.
  • initialValue: Initial value of T type that it will hold.
  • debugLabel: (optional) A label to identify the hook in the DevTools extension.

Properties & Methods

The UseAsyncState utility provides the following properties and methods to manage asynchronous states effectively:

  • value: A getter to retrieve the current state of T type. The value can either be the initialValue or the resolved value returned by the asyncFunction .
  • status: A getter to access the current status of the asynchronous state. The possible statuses are:
    • UseAsyncStateStatus.idle: Indicates that the state is in stand by and no operation is in progress.
    • UseAsyncStateStatus.loading: Indicates that an asynchronous operation is currently running.
    • UseAsyncStateStatus.done: Indicates that the asynchronous operation has completed successfully.
    • UseAsyncStateStatus.error: Indicates that an error occurred during the asynchronous operation.
  • isLoading: A boolean getter that returns true if the asyncFunction is currently in progress.
  • isDone: A boolean getter that returns true if the asyncFunction has successfully completed.
  • isError: A boolean getter that returns true if the asyncFunction has failed.
  • error: A getter that returns the error object if the asyncFunction has failed.
  • future: A getter that returns the Future of the asynchronous operation.
  • uValue: A reactive state object that provides the current value and notifies listeners when the value changes.
  • uStatus: A reactive state object that provides the current status and notifies listeners when the status changes.
  • uIsLoading: A reactive state object that provides a boolean indicating whether the asyncFunction is in progress, with notifications for changes.
  • uIsDone: A reactive state object that provides a boolean indicating whether the asyncFunction has completed, with notifications for changes.
  • uIsError: A reactive state object that provides a boolean indicating whether the asyncFunction has failed, with notifications for changes.
  • uError: A reactive state object that provides the error information and notifies listeners if an error occurs.
  • resolve : Executes the asyncFunction and updates the state asynchronously.
    • Syntax:
      FutureOr<T?> resolve();
      // For UseAsyncState.withArg
      FutureOr<T?> resolve(A arg);
  • cancel : Cancels the currently running asynchronous operation, if applicable.
    • Syntax:
      void cancel();
  • when : Evaluates and returns a value based on the current state. Useful for rendering or handling state-specific logic.
    • Syntax:
      R? when<R>({
      WhenValueReturn<T, R>? idle,
      WhenValueReturn<T, R>? loading,
      WhenValueReturn<T, R>? done,
      WhenErrorReturn<R>? error,
      });
    • parameters:
      • idle: A callback function invoked when the state is UseAsyncStateStatus.idle.
      • loading: A callback function invoked when the state is UseAsyncStateStatus.loading.
      • done: A callback function invoked when the state is UseAsyncStateStatus.done.
      • error: A callback function invoked when the state is UseAsyncStateStatus.error.
Properties and methods inherited from RtState
  • debugLabel: A string that represents the label of the state object for debugging purposes.
  • debugInfo: A map that contains debug information about the state object.
  • update : Executes a callback function and notify its observers that the state has changed. When it is invoked, it emits two lifecycle events to signal the state transition:
    • Lifecycle.willUpdate is emitted first, indicating the impending update.
    • Lifecycle.didUpdate is emitted once the update process is complete.
  • notify : Forces the state to notify its observers. Unlike update , it emits only the Lifecycle.didUpdate event, as it doesn’t involve any preparatory steps before the notification.
  • bind : Establishes a connection between the state and a specific instance. This connection allows the instance to reactively update based on changes to the state. By binding the state, the instance becomes aware of changes to the state and can appropriately reflect those changes in its behavior.
  • unbind : Releases the connection between the state and the instance. When unbinding, the instance will no longer receive updates from the state. This can be useful when an instance is no longer actively using the state or when it needs to detach from the state temporarily or permanently.
  • dispose : Is responsible for cleaning up the state and any associated observers or resources. Disposing of the state ensures that it is properly released and no longer consumes memory or processing resources unnecessarily.

Usage

Declaration

UseAsyncState can be initialized using the constructor class:

final uAsyncState = UseAsyncState<String>(asyncFunction, 'Initial value');
Future<String> asyncFunction() async {
await Future.delayed(Duration(seconds: 2));
return "Resolved value";
}

Resolving & reading the state

UseAsyncState has a resolve method that updates the state asynchronously by calling the asyncFunction function. After resolving the state, you can read the value, like this:

print("${uAsyncState.value}"); // Initial value
await uAsyncState.resolve();
print("${uAsyncState.value}"); // Resolved value

Using with argument

UseAsyncState can be used with arguments using the withArg constructor:

final uAsyncStateWithArg = UseAsyncState.withArg<String, int>(
asyncFunctionWithArg,
'Initial value',
);
Future<String> asyncFunctionWithArg(int arg) async {
await Future.delayed(Duration(seconds: 2));
return "Resolved value with arg: $arg";
}

To resolve the state with an argument, you can use the resolve method with the argument. After resolving the state, you can read the value, like this:

print("${uAsyncStateWithArg.value}"); // Initial value
await uAsyncStateWithArg.resolve(10);
print("${uAsyncStateWithArg.value}"); // Resolved value with arg: 10

If you want to add more arguments, you can supply it using the Record (if your proyect support) or Args (A generic arguments provided by Reactter), e.g.:

final uAsyncStateWithArgs = UseAsyncState.withArg<String, ArgsX3<String>>(
asyncFunctionWithArgs,
'Initial value',
);
Future<String> asyncFunctionWithArgs(ArgsX3<String> args) async {
await Future.delayed(Duration(seconds: 2));
return "Resolved value with args: ${args.arg}, ${args.arg2}, ${args.arg3}";
}
print("${uAsyncStateWithArgs.value}"); // Initial value
await uAsyncStateWithArgs.resolve(ArgsX3('arg1', 'arg2', 'arg3'));
print("${uAsyncStateWithArgs.value}"); // Resolved value with args: arg1, arg2, arg3

Caching the value

UseAsyncState doesn’t cache the resolving value by default, meaning that it will resolve the value every time resolve is called, potentially impacting performance, especially if the asyncFunction is expensive. In this case, you should consider using  Memo  to cache the resolving value, e.g.:

1
final uTranslateState = UseAsyncState.withArg<String?, ArgsX3<String>>(
2
/// `Memo` stores the value resolved in cache,
3
/// and retrieving that same value from the cache the next time
4
/// it's needed instead of resolving it again.
5
Memo.inline(
6
(ArgsX3<String> args) async {
7
final text = args.arg;
8
final from = args.arg2;
9
final to = args.arg3;
10
// this is fake code, which simulates a request to API
11
return await api.translate(text, from, to);
12
},
13
MemoSafeAsyncInterceptor(), // avoid to save in cache when throw a error
14
),
15
null,
16
);
17
18
await uTranslateState.resolve(ArgsX3('Hello', 'en', 'es'));

Using when method

UseAsyncState provides a when method that allows to computed a value depending on its status:

final result = uAsyncState.when(
idle: (value) => "Standby",
loading: (value) => "Loading",
done: (value) => "Done",
error: (error) => "Error: $error",
);
print("Result: $result");

Updating the value

Use update method to notify changes after run a set of instructions:

uAsyncState.update((value) {
uAsyncState.value = "New value";
});

Use notify method to force to notify changes.

uAsyncState.notify();

Listening to changes

When value has changed, the UseAsyncState will emit the following events(learn about it here):

  • Lifecycle.willUpdate event is triggered before the change in value or update method have been invoked.
  • Lifecycle.didUpdate event is triggered after the change in value or after update or notify methods have been invoked.

Example of listening to changes:

1
Rt.on(
2
myAsyncState,
3
Lifecycle.didUpdate,
4
(_, state) => print("State value has changed to: ${state.value}"),
5
);