记录fultter---provider的三种基本使用

158 阅读2分钟

分为四个步骤

今天又对这个状态管理有了新的认识,上一文中我是不懂,这次感觉也挺爽的,和vue差不多了。。。。。

1、引入provider库

     provider: ^6.0.2

2、创建需要共享的数据类

   还是要继承ChangeNotifier//1、创建共享数据
    class counterStore extends ChangeNotifier {
      int _count = 100;

      int get count => _count;
      set count(int value) {
        _count = value;
        //通知监听者,也就是通知那个组件使用了该属性
        notifyListeners();
      }
    }

3、直接使用ChangeNotifierProvider包裹住根组件

   void main() {
  //将provider放在顶层
  runApp(ChangeNotifierProvider(
    create: (ctx) => counterStore(),
    child: MyAPP(),
  ));
}

ctx为上下文。。。。。

4、第一种:Provider.of

 这种方法使用Provider.of<counterStore>(context).属性直接拿到数据。
   Widget build(BuildContext context) {
    int count = Provider.of<counterStore>(context).count;
    return Container(
        padding: EdgeInsets.fromLTRB(50, 0, 50, 0),
        child: ListView(
          children: [
            ElevatedButton(
              child: Text("$count"),
              onPressed: () {
                Navigator.pushNamed(context, "webSocketRoute");
              },
            ),
           ]
         )
      )
   }
   其弊端就是,只要使用这种方式拿到数据,真个组件都会重新bulider,重新渲染

4、第二种:Consumer(相对推荐)

    Consumer2<counterStore,useStore>可传递两个store
      现在有这么个需求,通过点击让count++,那么代码就:
       Consumer<counterStore>(
           builder: (ctx, countVM, child) {
              print(ctx);
              return ElevatedButton(
                child: Text("${countVM.count}"),
                onPressed: () {
                  //通过countVM拿到数据,并修改
                  countVM.count++;
                },
              );
            }),
      
builder有三个参数
    ctx,表示Consumer组件上下文,
    countVM,表示要数据共享的store,例如:counterStore
    child:用来存放一个静态的组件
使用这个Consumer,可以让静态组件进行重新渲染。。
例子如下:
咱们把Text("${countVM.count}")组件弄成一个静态的:
Text("静态数据")
   Consumer<counterStore>(
          builder: (ctx, countVM, child) {
            return ElevatedButton(
              child: child,
              onPressed: () {
                //通过countVM拿到数据,并修改
                countVM.count++;
              },
            );
          },
          child: Text("静态数据"),
     ),
Consumer的两个参数就出来了,child存放一个组件,而builder里面的child用来接收这个组件,
那么这个静态的组件就不会重新被渲染,大大降低了渲染消耗。。
优点只有使用Consumer包裹的组件才会重新执行其内置的builder,并且使用child能防止静态资源重新渲染。




4、第三种:selector(推荐)

  Selector<counterStore, counterStore>(
          selector: (ctx, countMV) => countMV,
          shouldRebuild: (prev, next) => false,
          builder: (ctx, countVM, child) {
            print("object");
            return ElevatedButton(
              child: Text("${countVM.count}"),
              onPressed: () {
                //通过countVM拿到数据,并修改
                countVM.count++;
              },
            );
          },
          child: Text("静态数据"),
      ),
代码有四个参数bulider、child和Consumer的参数是一样的不再介绍。。。。
Selector<counterStore, counterStore>(
          selector: (ctx, countMV) => countMV,
          shouldRebuild: (prev, next) => false,
          builder: (ctx, countVM, child) {
          },
          child:"",
      ),
 Selector<counterStore, changeStore>
 第一个参数表示咱们定义的共享数据,第二个表示将第一个进行变化的数据
  shouldRebuild: (prev, next) =>false||true
  如果为flase,页面不渲染,否则为渲染。。
      

5、多个store时

   将其封抽离出来
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'counterStore.dart';

List<SingleChildWidget> providers = [
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
  ChangeNotifierProvider(create: (ctx) => counterStore()),
];
在main中引入并使用
import 'store/storeList.dart';
void main() {
  //将provider放在顶层
  runApp(MultiProvider(
    providers: providers,
    child: MyAPP(),
  ));
}

6、总结对比

使用Provider.of会让其所在类重新渲染。

使用Consumer避免了整个类进行渲染,只渲染其包裹的组件,使用child创建静态组件,可避免重新渲染。

使用selector进行状态管理,除了拥有Consumer的功能外,还可改变使用的状态类,也可禁止其包裹的页面渲染,