👏 Visit my GitHub for more content. Click to go to GitHub

1 Understanding of state management

Recently after the completion of the project development, there is no task arrangement, on their own to the project to check the gaps. If there was one thing that was most inevitable in the development of Flutter, it was state management. In our own project, we use Provider for management. In fact, we still have a little vague about the basis of state management. The superficial understanding is that: avoid constantly building the page, and we should carry out targeted refresh (including: updating a text will also waste the performance of the whole page build at once).




1.0 Simple Understanding

So let's get down to business and talk about the more correct understanding, so THAT I don't confuse people here.

1. The purpose of state management is to separate the interface from the business. 2. When the functions of our applications are complex and diversified, there will be dozens or even hundreds of states in the application. At this time, we need to manage the states reasonably and effectively.Copy the code

Many people who switched from imperative programming frameworks (Android or iOS native developers) to declarative programming (Flutter, Vue, React, etc.) initially didn’t adapt because they needed a new perspective to think about the APP development model. The Flutter is a modern framework for declarative programming:

During the process of writing an application, there are a number of states that need to be managed, and it is the changes to these states that update the interface refresh:

1.1 InheritedWidget (Sharing Application state)

There are various Widgets in the Flutter. There are UI and functional components. The InheritedWidget is a functional component in the Flutter. Its data is passed from top to bottom in the Widget tree.

Using a sample:Copy the code
class StateManagementDemo extends StatefulWidget {
  @override
  _StateManagementDemoState createState() => _StateManagementDemoState();
}

class _StateManagementDemoState extends State<StateManagementDemo> {
  int _count = 0;
  void _increaseCount () {
    setState(() {
      _count += 1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return CounterProvider(
      count: _count,
      increaseCount: _increaseCount,
      child: Scaffold(
        appBar: AppBar(title: Text('StateManagementDemo'), elevation: 0.0,),
        body: CounterWrapper(),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: _increaseCount,
        ),
      ),
    );
  }
}

class CounterWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Counter(),);
  }
}

class Counter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final int count = CounterProvider.of(context).count;
    final VoidCallback increaseCount = CounterProvider.of(context).increaseCount;
    return Center(child: ActionChip(
      label: Text('$count'), onPressed: increaseCount,), ); } } class CounterProvider extends InheritedWidget { final int count; final VoidCallback increaseCount; final Widget child; CounterProvider({ this.count, this.increaseCount, this.child, }) : super(child: child); Static CounterProvider of(BuildContext Context) => context.inheritFromWidgetOfExactType(CounterProvider); UpdateShouldNotify (InheritedWidget oldWidget) {override bool updateShouldNotify(InheritedWidget oldWidget) {updateShouldNotify(InheritedWidget oldWidget) {return true; }}Copy the code






2 State management framework

In 2.0, you can manage the status in the following ways

1. SetState: The most important waysetState, sufficient to support smaller programs, all other methods will eventually need to be calledsetThe State. 2.Function Callback Dart Function is flexible enough to support template parameters. typedef FooChanged = void Function(int); typedef ValueChanged<T> = void Function(T value); One-way change notification, which can be combined with ObserverList to support multiple subscribers. The ChangeNotifier and ValueNotifier built into the Flutter can be considered similar schemes. 3. The Delegate can be considered multiple callback functions. Other languages have a similar pattern, and the name seems to come from Objective-C. Abstract class SpiderDelegate {/// category is null, crawl book whole site /// category not null, crawl book under the category void onBook(Book book, {Site site, Category category}); void onChapter(Book book, Chapter chapter); } 4.Sigslot comes from the classic programming pattern in Qt, which Dart can easily implement. This approach probably won't have much use in Flutter at all, but since Sigslot is the king of interface data and logic decoupling in C++, as evidenced by boost::signal(2), the list here is just a placeholder (I implemented one myself). typedef ValueCallback<E> = void Function(E value); abstract class Signable<E> { // Signable<bool> someValue; /// Register a closure to be called when the object notifies its listeners. void connect(ValueCallback<E> listener); /// Remove a previously registered closure from the list of closures that the /// object notifies. void disconnect(ValueCallback<E> listener); /// sink value changed void emit(E value); Signal<String> signalString; signalString.connect((String str) { // got the `str` changed here });Copy the code




2.1 scoped_model

Scoped_model is a Dart third-party library that provides functionality that allows you to easily pass a data model from a parent Widget to its descendants. In addition, it will re-render all children that use the model when the model is updated. It comes directly from a simple extract of the Model class from the Fuchsia core Widgets, a new system being developed by Google, and is released as a stand-alone Flutter plug-in for stand-alone use. The Scoped model uses the observer mode, where the data model is placed in the parent, and the offspring finds the parent's model to render the data, and finally sends the data back when the data changes, and the parent notifies all the children using the model to update the status.Copy the code




2.2 Redux

Redux is a one-way data flow architecture that makes it easy to develop, maintain, and test applications.Copy the code

We're in Redux, and all the states are stored in the Store. This Store is going to be on top of the App. The View takes the State stored in the Store and maps it to the View. The View also interacts with the user, the user clicks a button and swipes the screen and so on, and the data changes because of that interaction. Redux lets us not let the View directly operate data, but instead initiate an action to tell the Reducer that the state has changed. When the Reducer receives the action, it goes back to traversing the action table, finds the matching action, generates the new state based on the action, and puts the new state into the Store. The Store discards the old state object, stores the new state object, and notifies all View updates that use the state (similar)setThe State). So we can synchronize the state between different views.Copy the code




2.3 BLoC

BLoC is a way to build applications using reactive programming, a completely asynchronous world of flows.Copy the code

* Bundle stateful components with StreamBuilder, StreamBuilder will listen to a stream * this stream comes from BLoC * the data in the stateful widget comes from the monitored stream. * User interactive gestures were detected and an event was generated. Like pressing a button. * The StreamBuilder listens to the new data, generates a new snapshot and calls the build method again * The Widget is rebuiltCopy the code




2.4 RxDart

RxDart is a version of the ReactiveX standard API and is an extension of Stream from the Dart standard library. Therefore, RxDart has a slightly different term than Dart: Dart RxDart StreamController Subject Stream Observable is the same as Stream, and Subject is the same as StreamController. Unlike Dart, RxDart provides three variants of the StreamController that apply to different scenarios: PublishSubject BehaviorSubject ReplaySubjectCopy the code




2.5 Fish-Redux【 Recommended 👍】

Fish Redux is a modular Flutter application framework based on Redux data management. It is particularly suitable for building medium to large scale complex applications. It is characterized by configuration assembly. On the one hand, we will be a big page to view and data layers of dismantling for independent Component | Adapter, the upper is responsible for the assembly, the lower is responsible for the implementation; On the other hand, Component | Adapter into the View, Reducer, independent context-free function Effect, etc. So it will be very clean, easy to maintain, easy to collaborate. Fish Redux derives its inspiration from excellent frameworks like Redux, Elm, and Dva. And Fish Redux stands on the shoulders of giants and takes focus, divide, conquer, reuse, and isolate one step further.Copy the code




2.7 Provide

Like Scoped_model, Provide also uses InheritWidget to put the shared state on top of the top-level MaterialApp. The underlying component gets the state through Provier and notifies the components that depend on the state to refresh through the mixed ChangeNotifier. Provide also provides Provide. Stream, which allows us to process data in a stream manner, but there are some issues with it and it is not recommended.Copy the code




2.6 Provider【 recommended 👍👍👍】

In addition to supporting Flutter_Web, Google I/O 2019 announced that it was abandoning the previous state management Provide in favor of a similar library Provider. There's only one letter difference in how it's used; Learn about the new state management library Provider; Flutter provides a number of different providers for different types of objects; The Provider also uses InheritWidget to put the shared state on top of the MaterialApp;Copy the code






3 pits encountered in actual development

3.1 How to choose between Consumer and Selector in ⚠️Provider

When we need to update a page, we use notifyListeners(); But if we wrap a ListView with a Consumer and we print it we'll see that all the items that have been built are built again. This makes a little bit of sense, because we only need to update one of the items. And that's where it makes a big difference if we're dealing with selectors. It's just going to build the item that we need to update so it makes more sense. But when you're using selectors, the thing to notice about shouldRebuild is what does shouldRebuild use to decide whether to rebuildCopy the code


3.2 ⚠️Provider Uses Provider. Of (context) to obtain top-level data

If APage uses Provider.of(context) to get the top-level data, and then BPage makes changes to the data, it will actually affect APage and rerunning its build. In fact, wecommandClick on the "of" button to enter the underlying code and discover that there is also an argument "LISTEN" in addition to context. If we set LISTEN to APage:falseSo that the operation of BPage does not affect the APageCopy the code


3.3 ⚠ ️ SingleTickerProviderStateMixin and TickerProviderStateMixin pit

When using the vsync: "This", The State object must with SingleTickerProviderStateMixin or TickerProviderStateMixin We must first understand SingleTickerProviderStateMixin in TickerProviderStateMixin difference: TickerProviderStateMixin applies to many AnimationController SingleTickerProviderStateMixin applies to a single AnimationController Actually not have to use TickerProviderStateMixin, suggestion is to use SingleTickerProviderStateMixin. 1. Because if APage is used with TickerProviderStateMixin, you will find that the build method is called when jumping from APage to BPage or when returning from BPage to APage. 2. If you do not use With TickerProviderStateMixin, the build method is not called when jumping from APage to BPage or returning from BPage to APage.Copy the code











Copy the code

Reference:

State management

Flutter mobile application: State management

Flutter | state management guide – the Provider

Management of the eight Flutter states – In-depth commentary