declarative_async_widget 0.1.0 declarative_async_widget: ^0.1.0 copied to clipboard
FutureWidget and StreamWidget - Declarative FutureBuilder and StreamBuilder
FutureWidget and StreamWidget - Improved FutureBuilder and StreamBuilder. #
This package provides FutureWidget
and StreamWidget
, two widgets similar to StreamBuilder
and FutureBuilder
, which are designed to reduce
boilerplate and improve error handling.
It is a rewrite of the package async_builder
.
How it differs from async_builder
In async_builder
, multiple mutually exclusive events can coexist (e.g. giving both a stream
and a future
(which throws a runtime error), assigning both a waiting
and an initialData
, defining stream-only relevant params with a Future
, ...); declarative_async_widget
aims to address this and, at the same time, bring more clarity.
How to use #
1. Add to dependencies
dependencies:
declarative_async_widget: ^latest # replace latest with version number
2. Import
import 'package:declarative_async_widget/declarative_async_widget.dart';
FutureWidget #
The future
can't be null.
Constructors #
Default constructor
whenData
, whenError
and whenLoading
are required. initialData
can't be assigned since whenLoading
is going to be used instead.
class ExampleWidget extends StatefulWidget {
const ExampleWidget({Key? key}) : super(key: key);
@override
ExampleWidgetState createState() => ExampleWidgetState();
}
class ExampleWidgetState extends State<ExampleWidget> {
final Future<int> _getInt = myFuture(false);
static Future<int> myFuture(bool shouldThrow) async {
await Future.delayed(const Duration(seconds: 4));
if (shouldThrow) {
throw Exception("You can't pass true as a param");
}
return 4;
}
@override
Widget build(BuildContext context) {
return FutureWidget<int>(
future: _getInt,
whenData: (context, data) => Text('My data is: $data'),
whenError: (context, error, stackTrace) => Text('Error was thrown: $error'),
whenLoading: (context) => const Text('Loading...'),
);
}
}
noError
constructor
There is no whenError
param. Make 100% sure the future can't throw an error, else an AsyncWidgetUnexpectedError
will be thrown at runtime.
class ExampleWidgetState extends State<ExampleWidget> {
final Future<int> _getInt = myFuture();
static Future<int> myFuture() async {
await Future.delayed(const Duration(seconds: 4));
return 4;
}
@override
Widget build(BuildContext context) {
return FutureWidget<int>.noError(
future: _getInt,
whenData: (context, data) => Text('My data is: $data'),
whenLoading: (context) => const Text('Loading...'),
);
}
}
noLoading
constructor
There is no whenLoading
param, since in this case some initial data is present/given before the future has even fired; an initialData
argument is therefore required.
class ExampleWidgetState extends State<ExampleWidget> {
final Future<int> _getInt = myFuture(true);
static Future<int> myFuture(bool shouldThrow) async {
await Future.delayed(const Duration(seconds: 4));
if (shouldThrow) {
throw Exception("You can't pass true as a param");
}
return 4;
}
@override
Widget build(BuildContext context) {
return FutureWidget<int>.noLoading(
future: _getInt,
whenData: (context, data) => Text('My data is: $data'),
initialData: 99999,
whenError: (BuildContext context, Object error, StackTrace? stackTrace) =>
Text('Error was thrown: $error'),
);
}
}
onlyData
constructor
This constructor integrates noError
and noLoading
. Therefore:
- no
whenError
param - no
whenLoading
param initialData
is required
class ExampleWidgetState extends State<ExampleWidget> {
final Future<int> _getInt = myFuture();
static Future<int> myFuture() async {
await Future.delayed(const Duration(seconds: 4));
return 4;
}
@override
Widget build(BuildContext context) {
return FutureWidget<int>.onlyData(
future: _getInt,
whenData: (context, data) => Text('My data is: $data'),
initialData: 99999,
);
}
}
Additional Params #
/// Whether or not the state of this widget should be disposed (and therefore
/// the widget rebuilt) when the [future] instance changes.
///
/// If false, the current data should be retained.
final bool disposeOnFutureChange;
/// Whether or not to print errors to the console.
final bool printErrorsToConsole;
/// If provided, overrides the function that prints errors to the console.
final void Function(FlutterErrorDetails details) reportError;
/// Whether or not we should send a keep alive
/// notification with [AutomaticKeepAliveClientMixin].
final bool keepAlive;
StreamWidget #
It is similar to FutureWidget
, but uses streams. Examples will be added in the future.
Issues with type inference #
Remember to specify the type, e.g., FutureWidget<int>.onlyData
and not FutureWidget.onlyData
, otherwise a dynamic or a nullable type might be inferred (e.g. the type returned by future
is int
, however FutureWidget
's inferred type is int?
, i.e., FutureWidget<int?>
).
Note #
Complete documentation and tests will be added in the future.