Package selection guidance compiled from public package information, community data, and project usage.
Futuristic is a Flutter/Dart package that enables safe execution and retry logic for Futures within StatelessWidget widgets. It simplifies handling asynchronous operations in stateless contexts by providing a clean, declarative API to manage loading states, errors, and retries without requiring state management. The package integrates seamlessly with Flutter's widget tree and supports all major platforms. It’s ideal for scenarios where you need to fetch data or perform async tasks while maintaining a responsive UI.
Use cases
Fetching data in stateless widgets
Implementing retry logic for failed async operations
Displaying loading and error states
Building dynamic UIs with async content
Simplifying async handling in functional components
Key features
Safe Future execution in StatelessWidgets
Built-in retry mechanism
Support for loading and error states
Minimal boilerplate
Cross-platform compatibility
Suitable for
Developers using StatelessWidget extensively
Teams avoiding complex state management
Projects needing simple async handling
UIs with frequent data fetching
Apps targeting multiple platforms
Considerations
Not suitable for complex stateful logic
Limited to basic retry strategies
Requires understanding of Futures and async/await
May not replace full state management solutions
Best for lightweight async operations
Original README
Original README snapshot from the linked source repository. Visit the repository for the latest content.
futuristic
Makes it possible to safely execute and retry a Future inside a StatelessWidget.
See the Mainstream package for a similar API for working with Streams.
Problem
If you've ever tried to use the FutureBuilder widget in Flutter, you've probably been surprised by its behavior. When used inside a StatelessWidget, it will re-execute its Future every time it is rebuilt. Since a widget can be rebuilt many times in Flutter (including due to hot reload), this can be undesirable if our Future calls a non-idempotent REST API endpoint, for example.
classHomeextendsStatelessWidget{
@overrideWidgetbuild(BuildContext context) {
returnFutureBuilder(
future: myExpensiveFuture(), //Will be executed every time Home is rebuilt
builder: (_context, snapshot) {
...
},
);
}
}
To execute our Future only once, we could use a StatefulWidget, but now we have the extra boilerplate of using a StatefulWidget and holding onto our Future in a state variable.
classHomeextendsStatefulWidget{
@overrideState<Home> createState() => _HomeState();
}
class_HomeStateextendsState<Home> {
Future _future;
@overridevoidinitState() {
super.initState();
_future = myExpensiveFuture();
}
@overrideWidgetbuild(BuildContext context) {
returnFutureBuilder(
future: _future, // Will be executed only once
builder: (_context, snapshot) {
...
},
);
}
}
Solution
The problem with FutureBuilder is, ironically, that it takes a Future instance as its input. Instead, the Futuristic widget takes a Function that returns a Future and holds onto it in its own State. This means:
It can be used in a StatelessWidget.
It can let child widgets start or retry a Future.
Additionally, Futuristic provides:
Multiple builder callbacks to provide mutually exclusive initial/busy/data/error widget states.
Optional onData/onError callbacks to perform additional actions when a Future succeeds or fails.
Generic type safety for the data provided to callbacks. The type parameter <T> can be omitted if it can be inferred from the futureBuilder function.
Usage
We can use the Futuristic widget to wrap a single component like a button, or even an entire screen.
Button example
To start executing a Future in response to a button press, connect its onPressed handler to the start function provided in the initialBuilder callback.
The initialBuilder parameter is required if autoStart is false (see example below).
The optional busyBuilder displays a widget when the Future is busy executing. By default, it shows a centered CircularProgressIndicator. By displaying this, we inform the user that the operation is in progress and also prevent the Future from being triggered twice accidentally.
The optional errorBuilder displays a widget when the Future has failed, typically with an Error or Exception. This is provided as a parameter, together with a retry function that can be called to "retry" the Future.
The optional dataBuilder displays a widget when the Future has succeded. The resulting T value of the Future<T> is provided as a parameter to the callback. Note that this will be null in the case of a Future<void>.
Screen example
To automatically start executing a Future upon navigating to a screen, set the autoStart parameter to true instead of providing an initialBuilder. The busyBuilder will be displayed immediately.
The optional onError callback can be used to handle the error event by displaying an alert dialog or sending to a logging provider, for example. It can be used in place of or together with the errorBuilder. A retry function is provided as a parameter that can be called to "retry" the Future. Be careful not to call retry without user interaction to avoid creating an infinite loop. This callback will not be retriggered as a result of a widget rebuild.
The optional onData callback can be used to handle a successful result by displaying an alert dialog or performing navigation. for example. This can be used in place of or together with the dataBuilder. This callback will not be retriggered as a result of a widget rebuild.