Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

In addition to support for Flutter_Web, another big news at Google I/O 2019 was to deprecate state management Provide and recommend similar library providers instead. Although there is only one letter difference in the use of a great deal of difference; Small dish preliminary study new state management library Provider;

Flutter provides a variety of providers for different types of objects. The Provider also uses the InheritWidget to place shared state on top of the top-level MaterialApp.

The Provider way

The most basic state management mode, in a parameter binding and display;

1. Bind data

The Provider can perform data binding at the required widgets:

const Provider.value({
    Key key,
    @required T value,
    this.updateShouldNotify,
    this.child,
})  : dispose = null,
        super.value(key: key, value: value);
Copy the code

Value analysis source code Provider. Value does not limit the value type, we can bind the data type according to the demand; When determining the binding data type, it is recommended to add the data type during the binding, for example: provider.value (value: “, child:);

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: Provider<String>.value( value: 'FirstPage Provider', child: MyHomePage(title: 'Peovider Demo'))); }}Copy the code

2. Obtain data

The Provider needs to be retrieved in the child Widget of the data binding; Use the static method provider.of (BuildContext Context), which looks up the latest data of the same type from the Widget Tree associated with BuildContext for presentation; No abnormal report;

Text('${Provider.of<String>(context)}'),
Text('FirstPage Provider: ${Provider.of<String>(context)} | ${Provider.of<int>(context)} | ${Provider.of<bool>(context)}}'),
Copy the code

3. Bind multiple data

In our actual development, we will not bind only one data. When binding multiple data, we can use the following two ways: nested binding and aggregated binding; The two methods have the same effect. The side dishes prefer MultiProvider binding, with clearer and concise hierarchy.

Class MyApp extends StatelessWidget {@override Widget Build (BuildContext context) {return MaterialApp(title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: Provider<User>.value( value: new User('Flutter', 300), child: Provider<int>.value( value: 200, child: Provider<bool>.value( value: false, child: MyHomePage(title: 'Peovider Demo'))))); Class MyApp extends StatelessWidget {@override Widget Build (BuildContext context) {return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MultiProvider(providers: [ Provider<User>.value(value: new User('Flutter', 300)), Provider<int>.value(value: 200), Provider<bool>.value(value: false) ], child: MyHomePage(title: 'Peovider Demo'))); }}Copy the code

4. Bind data types

The data types bound to the Provider are flexible, not just basic data types. A User class is defined for normal status management. The User obtained after resetting the name is the latest data;

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MultiProvider(providers: [ Provider<User>.value(value: new User('Flutter', 300)), Provider<int>.value(value: 200), Provider<bool>.value(value: false) ], child: MyHomePage(title: 'Peovider Demo'))); } } Text( 'FirstPage Provider: ${Provider.of<String>(context)} | ' '${Provider.of<int>(context)} | ${Provider.of<bool>(context)} | ${Provider.of<User>(context).name = 'Hello World! '}', style: TextStyle(color: Colors.redAccent)), Text('${Provider.of<User>(context).name}'),Copy the code

5. The scope

The Widget is stuck in the scope at the beginning of the learning process. The actual documentation makes it clear that the scope for retrieving the bound data is in the child Widget of the bound data. Xiao CAI has drawn a personal understanding of the basic scope map, if there is any error, please give more guidance;

      void main() => runApp()Is the most extensiveApplication scope, its scope of action includes variousPageBetween;FirstPageDefined in theProvider AIn the blue box,Provider BIn the pink box,SecondPageDefined in theProvider CIn the green range; Out of range, state management cannot be carried out;

6. Scope content

Value (value: “, child:); if it is a String of state management Provider (value: “, child:); If not, search for the blue scope of the previous layer; if there is, bind data to the blue box; If the application scope is still not found, the application scope binding data is displayed. If there is no abnormal report;

This also validates the scope of the child widgets mentioned in the documentation, looking up the outer widgets layer by layer until they are available;

ChangeNotifierProvider way

By calling ChangeNotifier notifyListeners ChangeNotifier for listening, to be exposed to the dependency of its child widgets and reconstruction;

1. Bind data

ChangeNotifierProvider binds data in two ways:

  1. ChangeNotifierProvider({Key key, @required ValueBuilder builder, Widget child })

Create a ChangeNotifier through the constructor, which is handled automatically when the ChangeNotifierProvider is removed.

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider<User>( builder: (_) => User('Flutter', 0), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}Copy the code
  1. ChangeNotifierProvider.value({Key key, @required T notifier, Widget child })

Listen for notifications to child widgets and rebuild dependencies;

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider<User>.value( notifier: User('Flutter', 0), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}Copy the code

2. Obtain data

Retrieving data is similar to using a Provider directly;

Text('${Provider.of<User>(context).getName}'),
Copy the code

Compared with Provider, ChangeNotifierProvider is more flexible. You can rewrite the GET /set method to modify and use the status management.

// User entity Bean class User with ChangeNotifier {var name; var age; User(this.name, this.age); void setName(String name) { this.name = name; notifyListeners(); } String get getName => this.name; } Provider class MyApp extends StatelessWidget {@override Widget Build (BuildContext context) {return ChangeNotifierProvider<User>( builder: (_) => User('Flutter', 0), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); } // Get Provider data Expanded(child: TextField(onChanged: (changed) => Provider.of<User>(context).setName(changed), controller: _phonecontroller, decoration: SuffixIcon: IconButton(icon: icon (Icons. Clear, color: colors.black45), onPressed: () { _phonecontroller.clear(); })))), Text('${Provider.of<User>(context).getName}'),Copy the code

The problem summary

“Could not find the correct Provider… After testing, we found that the corresponding binding data was not found in the hierarchical search of the child Widget. Most likely, the location of the Widget to which the data is bound is unbound or incorrectly bound;


Xiao CAI’s understanding of Provider is still very simple, and the use of other providers has not been tried. If there are mistakes, please guide!

Source: Little Monk A Ce