Flutter state management mode - learning the basic usage of providers

1. What is a provider

Provider is used by Google to replace the previous state management Provider. Although there is only one letter difference, the usage is very different. Flutter provides a variety of Providers for different types of objects; Providers also use InheritWidget to put the shared state on the top-level MaterialApp.

Provider can provide you with:

  • Simplify resource allocation/disposition
  • lazy loading
  • Significantly reduces boilerplate when making a new class every time
  • devtools-friendly
  • Common ways to use these InheritedWidgets (see Provider.of/Consumer/Selector)
  • The complexity of the listening mechanism grows exponentially, increasing the scalability of the class (e.g. ChangeNotifier, which is O(N²) for scheduling notifications)

Second, the use of Provider components

Because the project uses provider: ^4.0.4, this version is the main one.
Now that it is 5.0.0, I probably took a look at the update and optimized it a lot. If you are interested, you can go and have a look.

Basic usage of Consumer
Create a new data provider class, which is mainly used to provide data

class DataProvider extends ChangeNotifier{
    
    
  int count=0;
  int count1=0;


  void add(){
    
    
    count++;
    print("count:$count");
    notifyListeners();
  }
  void add1(){
    
    
    count1++;
    print("count1:$count1");
    notifyListeners();
  }

}

```bash
    return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Column(
        children: <Widget>[
          Consumer<DataProvider>(builder: (_, data, __) {
    
    
            print("text1 rebuild");
            return Text(data.count.toString());
          }),
          Consumer<DataProvider>(builder: (_, data, __) {
    
    
            print("text2 rebuild");
            return Text(data.count1.toString());
          }),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count"),
              ),
            ),
          ),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count1"),
              ),
            ),
          ),
        ],
      ),
    );

operation result:

I/flutter (24104): count:1
I/flutter (24104): text1 rebuild
I/flutter (24104): text2 rebuild

Other ways to write consumer

class ChildAWidget extends StatelessWidget {
    
    
  final Widget child;
  final dynamic data;

  ChildAWidget({
    
    this.child, this.data});

  @override
  Widget build(BuildContext context) {
    
    
    print("ChildAWidget build");
    return Container(
      child: Column(
        children: <Widget>[Text("$data" ?? "ChildAWidget"), child],
      ),
    );
  }
}

class ChildBWidget extends StatelessWidget {
    
    
  @override
  Widget build(BuildContext context) {
    
    
    print("ChildBWidget build");
    return GestureDetector(
      onTap: () {
    
    
        Provider.of<DataProvider>(context).add();
      },
      child: Container(
        child: Text("点我啊"),
      ),
    );
  }
}

 return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Consumer<DataProvider>(
        builder: (_, data, child) => ChildAWidget(
          child: child,
          data: data.count,
        ),
        child: ChildBWidget(),
      ),
    );

In this example, ChildBWidget is redrawn outside the builder. Then the ChildAWidget instance is passed to the builder as the last parameter.
This means that when the builder is called repeatedly, the Consumer does not create new instances of ChildBWidget. This lets Flutter know that ChildBWidget doesn't have to be repainted. So with such a writing method, when the DataProvider is updated, only ChildAWidget will redraw.

selector basic usage

    return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Column(
        children: <Widget>[
          Selector<DataProvider, int>(selector: (_, store) => store.count, builder: (_, data, __){
    
    
            {
    
    
              print("text1 rebuild");
              return Text(data.toString());
            }
          }),
          Selector<DataProvider, int>(selector: (_, store) => store.count1, builder: (_, data, __){
    
    
            {
    
    
              print("text2 rebuild");
              return Text(data.toString());
            }
          }),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count"),
              ),
            ),
          ),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add1();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count1"),
              ),
            ),
          ),
        ],
      ),
    );

operation result:

I/flutter (24104): count:1
I/flutter (24104): text1 rebuild

other wording of selector

 return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Selector<DataProvider, int>(
        builder: (_, d, child) => ChildAWidget(
          child: child,
          data: d,
        ),
        shouldRebuild: (pre,next)=>pre!=next,
        selector: (BuildContext c, DataProvider d) {
    
    
          return d.count;
        },
        child: ChildBWidget(),
      ),
    );

If you want to use multiple providers, you can use MultiProvider.

    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: DataProvider()),
        ChangeNotifierProvider.value(value: DataProvider1()),
      ],
      child: ChildCWidget(),
    );

3. Summary

In fact, there is not much difference in usage between consumer and selector. The difference is that as long as the value of consumer changes, it will notify its host to refresh the UI, while selector can select some values ​​to update. The granularity of selector control is finer than that of consumer. Consumer monitors the changes of all data in a provider, while selector monitors the changes of one or more values. It can be seen from the above operation results.

There are still some provider components that are not introduced, and I basically write them only when I use them in projects. Alright, I'm done with Sahua, and I've recorded another learning process.

Guess you like

Origin blog.csdn.net/hjjdehao/article/details/114948377