How to Use Provider for State Management in Flutter || Part - 2

In Flutter, managing state efficiently is crucial for building responsive and dynamic applications. In the first part of this series, we explored the basics of using the Provider package for state management. In this second part, we will delve deeper into FutureProvider and StreamProvider, two powerful tools that help handle asynchronous data in Flutter apps. By understanding how to use these providers, you can ensure your app remains responsive and provides a seamless user experience. If you missed the first part, you can check it out here.
What is FutureProvider?
In Flutter, FutureProvider is a part of the Provider package, which helps manage state in your app. Let me explain what it does:
Purpose of
FutureProvider:FutureProvideris used to provide a value that might not be ready when the widget tree is built. It ensures that a null value isn’t passed to any widgets.The main use-case is to handle asynchronous operations (like fetching data from an API) and provide the result to widgets once the future is completed.
How it works:
You wrap your widget tree with a
FutureProvider.The
FutureProvidertakes aFutureclass (e.g., an API call) and updates the widgets depending on it when the future completes.Until the future resolves, you can provide an initial value (e.g., a loading spinner) to avoid null errors.
Example:
FutureProvider<String>( create: (_) => fetchDataFromApi(), // Your async operation initialData: 'Loading...', // Initial value child: MyWidget(), )
Remember, FutureProvider is particularly useful when dealing with asynchronous data in your Flutter app!
How to use FutureProvider in a Flutter app?
In Flutter, FutureProvider from the Provider package is used to handle asynchronous operations and provide the result to widgets once the future completes. Here’s how you can use it:
Exposing an Immutable Value:
If you have an “immutable value” that needs to be asynchronously loaded (e.g., a config file), use
FutureProviderlike this:FutureProvider<MyConfig>( builder: (_) async { final json = await // Load JSON from somewhere (e.g., an API); return MyConfig.fromJson(json); }, )
Combining with Mutations:
To convert a
Futureinto something easier to manipulate, combineFutureProviderwith a mutable object (likeChangeNotifier):ChangeNotifierProvider( builder: (_) => Foo(), child: Consumer<Foo>( builder: (_, foo, __) { return FutureProvider.value( value: foo.someFuture, child: ... // Your widget tree ); }, ), )This allows you to handle updates when the future completes.
Remember, FutureProvider is particularly useful for managing asynchronous data in your Flutter app!
What is StreamProvider?
In Flutter, StreamProvider is a state management solution that leverages the power of the Dart Stream API and the simplicity of Flutter’s Provider package. Here’s what you need to know:
Purpose of StreamProvider:
Exposing a Stream: StreamProvider is used to expose a stream and allows its descendants to access the latest value emitted by that stream.
Listening to Changes: It listens to the stream and automatically updates the widgets when new data arrives.
How to Use StreamProvider:
Wrap your widget tree with StreamProvider:
StreamProvider<int>( create: (_) => myStream, // Your stream (e.g., from Firestore, WebSocket, etc.) initialData: 0, // Initial value child: MyWidget(), )Replace
intwith the type of data your stream emits (e.g.,String,List<User>, etc.).
Difference Between StreamProvider and StreamBuilder:
StreamBuilder: Rebuilds itself every time the stream updates. It’s a built-in Flutter widget.
StreamProvider: Combines
StreamBuilderwithInheritedWidget, allowing efficient data passing through the widget tree.
How to use StreamProvider in a Flutter app?
In your Flutter app, StreamProvider is a powerful way to handle asynchronous data using streams. Let’s dive into how you can use it:
Import the Necessary Packages: First, make sure you have the
providerpackage added to yourpubspec.yamlfile:dependencies: flutter: sdk: flutter provider: ^6.1.2Create a StreamProvider: Wrap your widget tree with
StreamProvider. Specify the type of data your stream emits (e.g.,Stream<int>orStream<List<User>>):StreamProvider<int>( create: (_) => myStream, // Your stream (e.g., from Firestore, WebSocket, etc.) initialData: 0, // Initial value child: MyWidget(), )Access the Stream in Your Widgets: Inside
MyWidgetor any descendant widget, usecontext.watchorcontext.readto access the stream:final myValue = context.watch<int>(); // Access the stream valueUpdate UI When Stream Emits Data: Whenever your stream emits new data, the widgets wrapped by
StreamProviderwill automatically rebuild with the updated value.
Remember, StreamProvider simplifies handling asynchronous data in your app!
What is ValueListenableBuilder in flutter?
Certainly! The ValueListenableBuilder in Flutter is a handy widget that keeps its content in sync with a ValueListenable. Here’s how it works:
What is
ValueListenableBuilder?ValueListenableBuilderis a widget that listens to changes in aValueListenableand automatically rebuilds its content when the value changes.You provide a
ValueListenable<T>and a builder function that creates widgets based on the current value of theValueListenable.When the value changes, the builder function is called with the updated value, allowing you to update your UI accordingly.
Usage Example:
ValueListenableBuilder<int>( valueListenable: myValueListenable, // Your ValueListenable instance builder: (BuildContext context, int value, Widget? child) { // Build your UI based on the current value return Text('Count: $value'); }, )Performance Optimisation:
If your builder function contains a subtree that doesn’t depend on the
ValueListenablevalue, you can pass a pre-built subtree as thechildparameter.This pre-built child is optional but can significantly improve performance in some cases.
Other Similar Widgets:
AnimatedBuilder: Rebuilds based on aListenablewithout passing back a specific value.NotificationListener: Rebuilds based on notifications from descendant widgets.StreamBuilder: For more advanced use cases involving streams.TweenAnimationBuilder: Animates values based on aTween.
Remember to replace myValueListenable with your actual ValueListenable instance.
How to create your own ValueNotifier in Flutter?
Certainly! Creating your own ValueNotifier in Flutter is straightforward. It’s a simple class that extends ChangeNotifier and provides a way to store a single value that can be listened to and updated reactively. Let’s walk through an example:
import 'package:flutter/material.dart';
class CounterModel extends ValueNotifier<int> {
CounterModel(int value) : super(value);
void increment() => value++;
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = CounterModel(0);
return MaterialApp(
title: 'ValueNotifier Demo',
home: Scaffold(
appBar: AppBar(
title: Text('ValueNotifier Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
ValueListenableBuilder(
valueListenable: counter,
builder: (BuildContext context, int value, Widget? child) {
return Text(
'$value',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counter.increment();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
}
}
In this example:
We define a
CounterModelclass that extendsValueNotifier<int>.The
increment()method updates the counter value.We create an instance of
CounterModeland pass it toValueListenableBuilder, which listens to changes in the counter value and rebuilds the widget tree when the value changes.
Using ValueNotifier is that simple! It's a great choice for small to medium-sized projects where you don't need the complexity of other state management solution. keep in mind that for larger or more complex projects, other state management solutions like Riverpod, Provider, Bloc, or Redux might be more suitable.
In this article, we explored
FutureProviderandStreamProviderin Flutter. These tools help manage asynchronous data, ensuring your app remains responsive and dynamic. By using these providers, you can efficiently handle state management in your Flutter applications.





