An overview of the

From imperative programming frameworks (iOS, Android) to declarative programming (Flutter, VUE), for example, Flutter has a large number of states that need to be managed. When data is shared,

classification

  • Briefly state

Some simple data changes can be managed by using the State class of statefulWidget itself

  • Application status AppState

For example, select the global status management mode for user information and global data information

Share Status Management

InheritedWidget

Define an InheritedWidget that shares data and needs to inherit the InheritedWidget

  • You need to define aofStatic method, passed incontextStart to find outThe ancestorsThe data of
class ShareWidget extends InheritedWidget {
  // Share counter data
  final int counter;
  ShareWidget({this.counter, Widget child}) : super(child: child);
  
  static ShareWidget of(BuildContext context) {
    // Find the nearest ancestor widget along the context
    return context.dependOnInheritedWidgetOfExactType();
  }

  @override
  bool updateShouldNotify(covariant ShareWidget oldWidget) {
    // Whether data changes need to be notified
    return this.counter != oldWidget.counter;
  }
}
Copy the code

Use of other widgets

@override
Widget build(BuildContext context) {
  // Get the "ShareWidget" by calling the static method of
  int _counter = ShareWidget.of(context).counter;
  return Container(
    child: Text("$_counter")); }Copy the code

Provider

An official recommended global status management tool

Dependencies: the provider: ^ 4.0.4Copy the code

Three concepts

  • ChangeNotifier: Place where real data (status) is stored
  • ChangeNotifierProvider: The place in the widget tree where the data is provided, the corresponding ChangeNotifier is created
  • Consumer: The part of the Widget tree where data (state) is needed

Basic usage of Provider

1.1 create the provider

Inherited from ChangeNotifier

class ViewModelProvider extends ChangeNotifier {
  // 1. Create the data you want to share
  int _counter = 100;

  int get counter => _counter;

  set counter(intvalue) { _counter = value; notifyListeners(); }}Copy the code

1.2 insert the provider

Put the ChangeNotifierProvider at the top of your application so that the ViewModelProvider is available globally

void main() {
  runApp(ChangeNotifierProvider(
      create: (ctx) => ViewModelProvider(), child: HomePage()));
}
Copy the code

1.3 Usage Data

1.3.1. The Provider of
int _counter = Provider.of<ViewModelProvider>(context).counter;
Copy the code
1.3.2 Consumer
  • Use Consumer wrapping to use widgets that share data
  • The Builder returns three parameters
    • contextReturns the current tree position
    • providerYou can use data in provider for instance corresponding to ChangeNotifier
    • childThe purpose is to prevent the child from being built repeatedly
  • Of course, with Consumer, widgets returned from builder (such as the FloatingActionButton in demo) will still be built repeatedly, so introducedSeletor
floatingActionButton: Consumer<ViewModelProvider>(
  child: Icon(Icons.add),
  // Builder returns context, provider, and child
  builder: (cxt, provider, child) {
    returnFloatingActionButton( child: child, onPressed: () { setState(() { provider.counter++; }); }); },),Copy the code
1.3.3 the Selector

The key parameters

  • 1. Generic parameter
    ,s>
    • A: We are going to use A provider this time
    • S: The converted data type
  • 2. Seletor callback function
    • The converted callback function, which without the conversion can return the instance of the Provider directly
  • 3. Check whether rebuild is required
Selector({
  Key? key,
  required ValueWidgetBuilder<S> builder,
  required S Function(BuildContext, A) selector,
  ShouldRebuild<S>? shouldRebuild,
  Widget? child,
})
Copy the code
floatingActionButton: Selector<ViewModelProvider, ViewModelProvider>(
  selector: (cxt, provider) => provider,
  shouldRebuild: (pre, next) => false,
  builder: (cxt, provider, child) {
    print("Selector build");
    returnFloatingActionButton( onPressed: () { provider.counter++; }, child: child, ); },),Copy the code
1.3.4 MultiProvider

There is definitely more than one provider in development, and it is not possible to nest all of them in runApp, so use MultiProvider

You can define a Dart class to hold providers

List<SingleChildWidget> providers = [
  ChangeNotifierProvider(
    create: (ctx) => Provider1(),
  ),
  ChangeNotifierProvider(
    create: (ctx) => Provider2(),
  ),
];
Copy the code
void main() {
  runApp(
    MultiProvider(
      / / use
      providers: providers,
      child: HomePage(),
    ),
  );
}
Copy the code

Use the summary

* 1. Create a data Provider extends ChangeNotifier * 2. Add ChangeNotifierProvider * 3 to runApp at the top of the application. Use shared data * 1) Provider. Of <ViewModelProvider>(context) * 2) Consumer * 3) Selector * 4 elsewhere. Use MultiProvider to manage multiple share statesCopy the code