Last updated:
0 purchases
async phase notifier
A variant of ValueNotifier that has AsyncPhase representing the initial /
waiting / complete / error phases of an asynchronous operation.
AsyncPhaseNotifier + AsyncPhase is similar to AsyncNotifier + AsyncValue of Riverpod.
Unlike AsyncNotifier and AsyncValue, which are tied to package:riverpod,
AsyncPhaseNotifier and AsyncPhase have no such binding. The notifier can be
used as just a handy variant of ValueNotifier with AsyncPhase as its value
and convenient methods for manipulating the phases.
Sample apps #
Useless Facts - simple
pub.dev explorer - advanced
Usage #
runAsync() #
The runAsync() method of AsyncPhaseNotifier executes
an asynchronous function, updates the value of AsyncPhaseNotifier automatically
according to the phase of the asynchronous operation, and notifies the listeners of
those changes.
The value of the notifier is switched to AsyncWaiting when the operation starts.
The change is notified to listeners.
The value is switched to either AsyncComplete or AsyncError depending on the
result.
The change is notified to listeners.
final notifier = AsyncPhaseNotifier<int>();
notifier.runAsync((data) => someAsyncOperation());
copied to clipboard
AsyncPhase #
The value of AsyncPhaseNotifier is either AsyncInitial,
AsyncWaiting, AsyncComplete or AsyncError.
They are subtypes of AsyncPhase.
AsyncPhase provides the when() and whenOrNull() methods,
which are useful for choosing an action based on the current phase, like returning
an appropriate widget.
child: phase.when(
initial: (data) => Text('phase: AsyncInitial($data)'), // Optional
waiting: (data) => Text('phase: AsyncWaiting($data)'),
complete: (data) => Text('phase: AsyncComplete($data)'),
error: (data, error, stackTrace) => Text('phase: AsyncError($data, $error)'),
)
copied to clipboard
async_phase is a separate package, included in this package. See
its document for details not covered here.
Listening for phase changes #
listen()
With listen(), you can trigger some action when the phase or its data changes.
This is not much different from addListener(), except for the following points:
Returns a function to easily stop listening.
Takes a listener function that receives the phase at the time of the call.
The listener is called asynchronously because this method uses Stream internally.
final notifier = AsyncPhaseNotifier<Auth>();
final cancel = notifier.listen((phase) { /* Some action */ });
...
// Remove the listener if it is no longer necessary.
cancel();
copied to clipboard
listenFor()
With listenFor(), you can trigger some action in one of the callbacks
relevant to the latest phase when the phase or its data changes.
Note:
All callbacks are optional.
Listener is not added if no callback function is passed.
The onWaiting callback is called when the phase has changed to AsyncWaiting and
also from AsyncWaiting. A boolean value is passed to the callback to indicate the
start or end of an asynchronous operation.
final notifier = AsyncPhaseNotifier<Auth>();
final cancel = notifier.listenFor(
onWaiting: (isWaiting) { /* e.g. Toggling an indicator */ },
onComplete: (data) { /* e.g. Logging the result of an operation */ },
onError: (e, s) { /* e.g. Showing an error dialog */ },
);
...
// Remove the listener if it is no longer necessary.
cancel();
copied to clipboard
AsyncPhaseListener
It is also possible to use the AsyncPhaseListener widget to
listen for phase changes.
child: AsyncPhaseListener(
notifier: notifier,
onWaiting: (isWaiting) { /* e.g. Toggling an indicator */ },
onComplete: (data) { /* e.g. Logging the result of an operation */ },
onError: (e, s) { /* e.g. Showing an error dialog */ },
child: ...,
)
copied to clipboard
Please note that a listener is added per each AsyncPhaseListener, not per
notifier. If this widget is used at various places for one certain notifier,
a single notification causes each of them to run its callback function.
Examples #
Here is WeatherNotifier extending AsyncPhaseNotifier. It fetches the weather
info of a city and notifies its listeners.
class WeatherNotifier extends AsyncPhaseNotifier<Weather> {
WeatherNotifier();
final repository = WeatherRepository();
void fetch() {
runAsync((weather) => repository.fetchWeather(Cities.tokyo));
}
}
copied to clipboard
final notifier = WeatherNotifier();
notifier.fetch();
copied to clipboard
The examples below use this notifier and show a particular UI component corresponding
to each phase of the fetch.
With ValueListenableBuilder #
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<AsyncPhase<Weather>>(
valueListenable: notifier,
builder: (context, phase, _) {
// Shows a progress indicator while fetching and
// either the result or an error when finished.
return phase.when(
waiting: (weather) => const CircularProgressIndicator(),
complete: (weather) => Text('$weather'),
error: (weather, e, s) => Text('$e'),
);
},
);
}
copied to clipboard
Or you can use AnimatedBuilder / ListenableBuilder in a similar way.
With Provider #
ValueListenableProvider<AsyncPhase<Weather>>.value(
value: notifier,
child: MaterialApp(home: ...),
)
copied to clipboard
@override
Widget build(BuildContext context) {
final phase = context.watch<AsyncPhase<Weather>>();
return phase.when(
waiting: (weather) => const CircularProgressIndicator(),
complete: (weather) => Text('$weather'),
error: (weather, e, s) => Text('$e'),
);
}
copied to clipboard
With Grab #
void main() {
runApp(
const Grab(child: App()),
);
}
copied to clipboard
@override
Widget build(BuildContext context) {
final phase = notifier.grab(context);
return phase.when(
waiting: (weather) => const CircularProgressIndicator(),
complete: (weather) => Text('$weather'),
error: (weather, e, s) => Text('$e'),
);
}
copied to clipboard
TODO #
❌ Add API documents
✅ Write tests
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.