Skip to main content

FutureProvider

FutureProvider is the equivalent of Provider but for asynchronous code.

FutureProvider is typically used for:

  • performing and caching asynchronous operations (such as network requests)
  • nicely handling error/loading states of asynchronous operations
  • combining multiple asynchronous values into another value

FutureProvider gains a lot when combined with ref.watch. This combination allows automatic re-fetching of some data when some variables change, ensuring that we always have the most up-to-date value.

info

FutureProvider does not offer a way of directly modifying the computation after a user interaction. It is designed to solve simple use-cases.
For more advanced scenarios, consider using StateNotifierProvider.

Usage example: reading a configuration file

FutureProvider can be a convenient way to expose a Configuration object created by reading a JSON file.

Creating the configuration would be done with your typical async/await syntax, but inside the provider. Using Flutter's asset system, this would be:

final configProvider = FutureProvider<Configuration>((ref) async {
final content = json.decode(
await rootBundle.loadString('assets/configurations.json'),
) as Map<String, Object?>;

return Configuration.fromJson(content);
});

Then, the UI can listen to configurations like so:

Widget build(BuildContext context, WidgetRef ref) {
AsyncValue<Configuration> config = ref.watch(configProvider);

return config.when(
loading: () => const CircularProgressIndicator(),
error: (err, stack) => Text('Error: $err'),
data: (config) {
return Text(config.host);
},
);
}

This will automatically rebuild the UI when the Future completes. At the same time, if multiple widgets want the configurations, the asset will be decoded only once.

As you can see, listening to a FutureProvider inside a widget returns an AsyncValue – which allows handling the error/loading states.