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
:FutureProvider
is 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
FutureProvider
takes aFuture
class (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
FutureProvider
like 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
Future
into something easier to manipulate, combineFutureProvider
with 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
int
with 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
StreamBuilder
withInheritedWidget
, 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
provider
package added to yourpubspec.yaml
file:dependencies: flutter: sdk: flutter provider: ^6.1.2
Create 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
MyWidget
or any descendant widget, usecontext.watch
orcontext.read
to access the stream:final myValue = context.watch<int>(); // Access the stream value
Update UI When Stream Emits Data: Whenever your stream emits new data, the widgets wrapped by
StreamProvider
will 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
?ValueListenableBuilder
is a widget that listens to changes in aValueListenable
and 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
ValueListenable
value, you can pass a pre-built subtree as thechild
parameter.This pre-built child is optional but can significantly improve performance in some cases.
Other Similar Widgets:
AnimatedBuilder
: Rebuilds based on aListenable
without 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
CounterModel
class that extendsValueNotifier<int>
.The
increment()
method updates the counter value.We create an instance of
CounterModel
and 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
FutureProvider
andStreamProvider
in 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.
Subscribe to my newsletter
Read articles from Fenisha Koladiya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by