preface
Today I happened to find a state management framework called Flutter -provide under Google dad’s repository. It was first submitted on February 8th, and it’s very new. After the simple use of the feeling is a word – cool! So today I’m going to share with you this new state management framework.
Providers are designed as an alternative to the ScopedModel and allow us to be more flexible with data types and data. But first, the cliche of state management.
Why do YOU need state management
When we first started building the application, it might have been simple. We have some states, and we just map them to views. This simple application may not require state management.
But as you add functionality, your application will have dozens or even hundreds of states. This is what your application should look like.
At this point, we urgently needed a framework to help us clarify these relationships, and a state management framework came into being.
What is the dojo.provide
Like Scoped_model, Provide uses an InheritWidget to place shared state on top of the top-level MaterialApp. The underlying component gets the state through Provier and refreshes the components that depend on the state through a ChangeNotifier blend.
Provide also provides Provide. Stream, which allows us to process data in the same way we process streams, although it is currently not recommended because of some problems.
Lets do it!
Here, we will use a simple app as an example to explain the use of Provide in detail. This involves sharing state and managing multiple states.
Both pages rely on two different states at the same time: Counter and Switcher. And when one page changes state, another changes state.
The complete code for the project is available on Github
Step 1: Add dependencies
Add a dependency on Provide in pubspec.yaml.
- , please refer to the actual pub.dartlang.org/packages/pr…
- For details, see juejin.cn/post/684490…
Step 2: Create the Model
Here it actually assumes the responsibility of State, but is called model to distinguish it from the official State.
import 'package:flutter/material.dart';
class Counter with ChangeNotifier{
int value = 0; increment(){ value++; notifyListeners(); }}Copy the code
Here we can see that the data and the means to manipulate the data are all in the Model, and we can clearly separate the business.
By comparing Scoped_model, we can see that in the Provide mode, the Model does not need to inherit the Model class, but only needs to implement Listenable. We have included ChangeNotifier to avoid managing the audience.
NotifyListeners are notified of updates.
Step 3: Put the state into the top layer
void main() {
var counter = Counter();
var providers = Providers();
// Add the counter object to providers
providers.provide(Provider<Counter>.value(counter));
runApp(
ProviderNode(
child: MyApp(),
providers: providers),
);
}
Copy the code
ProviderNode encapsulates the InheritWidget and provides a providers container for placing state.
ProviderScope provides a separate type space for providers, which allows multiple providers of the same type. ProviderScope(‘_default’) is used by default. You can specify the key by ProviderScope(“name”).
It is recommended to use provideFrom or provide methods when adding a set of providers, rather than provideAll, because it can check for compile-time type errors.
Provider<Counter>. Value wraps Counter as _ValueProvider. A StreamController is provided internally to enable streaming operations on data.
Step 4: Get the status
The same Provide also provides two ways to get State. Let’s start with the first, which is obtained through the Provide widget.
Provide<Counter>(
builder: (context, child, counter) {
return Text(
'${counter.value}', style: Theme.of(context).textTheme.display1, ); },),Copy the code
The Builder will rebuild the widget each time a data refresh is notified.
The Builder method takes three parameters, the second and third of which are covered here.
- Second argument child: If the widget is complex enough that there are internal widgets that won’t change, we can improve performance by writing those widgets in the Child property Provide so that the Builder doesn’t create those widgets repeatedly.
- Third parameter counter: This parameter represents the state of the top-level providers we get.
Scope: Gets the state corresponding to this key by specifying ProviderScope. Used when you need to use multiple states of the same type.
Provide. Value <T>(context)
final currentCounter = Provide.value<Counter>(context);
Copy the code
This way actually call context. InheritFromWidgetOfExactType _InheritedProviders find top to get to the top will of the state.
How do I organize multiple states
Unlike scoped_model, you can easily organize multiple states in the Provide mode. Just provide the state into the provider.
void main() {
var counter = Counter();
var switcher = Switcher();
varproviders = Providers(); providers .. provide(Provider<Counter>.value(counter)) .. provide(Provider<Switcher>.value(switcher)); runApp( ProviderNode( child: MyApp(), providers: providers) ); }Copy the code
Get data stream
There is a wrapper around adding counter to providers. We just learned from analyzing the source code that this operation allows us to work with streaming data.
Get the data stream by providing. Stream <T>(context). It is important to note that the data stream is retrieved each time
StreamBuilder<Counter>(
initialData: currentCounter,
stream: Provide.stream<Counter>(context)
.where((counter) => counter.value % 2= =0),
builder: (context, snapshot) =>
Text('Last even value: ${snapshot.data.value}')),
Copy the code
However, in my use, streamTransformer failed. Using the same code on both firstScreen and secondScreen, the Where method on secondScreen works, filtering out odd numbers, while the first screen receives complete data.
Note that a new stream is recreated each time the data stream is retrieved.
/// Creates a provider that listens to a stream and caches the last
/// received value of the stream.
/// This provider notifies for rebuild after every release.
factory Provider.stream(Stream<T> stream, {T initialValue}) =>
_StreamProvider<T>(stream, initialValue: initialValue);
Copy the code
There is some debate about this practice, please check out this issue: github.com/google/flut…
However, this functionality can also be used in conjunction with RxDart, which makes it easy to build an Observer through a stream, giving us more flexibility in organizing data.
Rebuild the widget from multiple states
We can use the ProvideMulti widget when a view might be rebuilt depending on multiple states.
The pit of known
Provide. Stream Creepy manual listening
Since Provide automatically wraps Listenable data and provides the Provide. Stream interface, we can listen on the stream to get the latest events. But this weird thing happens when we manually listen in.
...class _SecondScreenState extends State<SecondScreen> {
StreamSubscription<Switcher> _subscription;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_subscription = Provide.stream<Switcher>(context).listen((data){
print(data.toString());
});
}
@override
void dispose() {
unSubscribe();
super.dispose();
}
unSubscribe(){
if(_subscription ! =null){
_subscription.cancel();
_subscription = null; }}...Copy the code
This should receive an event when the data changes, but here we found that the flutter output was 5 at once: Instance of ‘Switcher’.
Why 5? Because I’ve listened to this data in 5 places, including once using the Provide Widget.
When I exit the second page and re-enter, I receive 5 more entries this time than last time.
This happens because the stream is created by the factory method, and each call to Provide. Stream recreates a stream. The stream exists even when the listener stops listening.
So don’t manually listen on your Provide. Stream.
Write in the last
It’s been three months since I last wrote the state Management extension Rxdart. The summary has not come out yet, I apologize for it here. State management itself is a novelty to me, so any summary that has not been tested in a large application is empty talk. That’s why I’ve been holding off on writing the summary. But HERE I can say some of their own feelings, for everyone’s reference.
In these months, I used BLoC more often, which is really flexible in organizing data and can easily realize lazy loading and other operations. And stateful widgets are written less and less. The downside is that the barrier to entry is high, and it took me a while to understand StreamTransformer and why I needed Pipe. The use of Bloc thinking requires a big change. I have seen many people use Bloc in projects, but it is very strange, and they are still thinking in the previous mode of thinking. Moreover, Bloc only organizes the data, and the shared state usually uses the InheritWidget, which requires a lot of extra work.
My second favorite is scoped_model because it is simple and easy to use. It was cheap to learn, and no template code was written.
The last thing I want to do with state management is redux. One is that it’s hard to get started, and I find asynchronous data processing rather cumbersome. But the idle fish team likes Redux and will open source fish_redux, a state management framework for idle fish. So maybe the app I’m writing isn’t complex enough to feel that way. Redux’s ability to divide responsibilities more clearly in complex applications, one-way data flow, and the fact that state is immutable are all benefits of Redux.
Finally, I’ll talk about Provide. Provide gave me an overall experience that was very close to Scoped, easy to use and much more powerful. Instead of inheriting, the Model simply implements Listenable to make it less intrusive. At the same time, the stream character is added, which is somewhat similar to what Bloc does. If you’ve used Scoped_model you’ll get the hang of it.
Suffice it to say, Provide is an excellent state management tool that you should use. However, there are still some problems in this package at present, such as Provide. Stream, which may undergo major changes in the future and needs to be used with caution.
This code has been uploaded to Github: github.com/OpenFlutter…
If you have any questions or suggestions on the Provide, please feel free to contact me in the comments section below or at my email address [email protected], and I will reply in time!