Provider 四种消费者
Provider.of
Provider.of 方法是 Provider 库中最常用的获取共享数据的方法之一。它接收一个 BuildContext 对象和一个泛型类型参数 T,会查找 Widget 树中最近的一个类型为 T 的 Provider 对象,并返回它所提供的共享数据。当共享数据发生变化时,它会自动重新构建与该共享数据有依赖关系的 StatefulWidget。
模型
class UserModel with ChangeNotifier {
  String name = "Jimi";
  int aa = 0;
  void changeName() {
    aa++;
    name = "hello"+aa.toString();
    print(name);
    notifyListeners();
  }
}
入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<UserModel>(
      create: (_) =>UserModel(),
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),
      );
  }
}
使用
class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("ConsumerExample"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              Provider.of<UserModel>(context).name,
              style: const TextStyle(color: Colors.red, fontSize: 50),
            ),
            Padding(
              padding: EdgeInsets.only(top: 20),
              child: ElevatedButton(
                onPressed: () {
                  Provider.of<UserModel>(context, listen: false)
                      .changeName(); //listen: false 必加
                },
                child: Text("点击加1"),
              ),
            )
          ],
        ),
      ),
    );
  }
}
*Consumer
Consumer 是一个轻量级的组件,用于消费共享数据并构建 UI。它接收一个 BuildContext 对象和一个 builder 函数作为参数,在 builder 函数中构建 UI,该 UI 依赖于共享数据。当共享数据发生变化时,Consumer 会自动重新构建 UI。
里面有三个属性:
- context: 当前的上下文
- **Provider.of(context):** 模型对象
- child: 子组件(不需要刷新的部分)
模型
String name = "Jimi";
int aa = 0; void changeName() {
aa++;
name = "hello$aa";
print(name);
notifyListeners();
}
}
入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<UserModel>(
      create: (_) =>UserModel(),
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),
      );
  }
}
使用
class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("ConsumerExample"),
      ),
      body: Consumer<UserModel>(
        builder: (_, UserModel userModel, child) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  userModel.name.toString(),
                  style: const TextStyle(color: Colors.red, fontSize: 50),
                ),
                Padding(
                  padding: const EdgeInsets.only(top: 20),
                  child: ElevatedButton(
                    onPressed: () {
                      userModel.changeName();
                    },
                    child: const Text("点击加1"),
                  ),
                ),
                Container(
                  //每次都需要加载
                  child: const Column(
                    children: [
                      Text("更多组件1"),
                      Text("更多组件2"),
                      Text("更多组件3"),
                      Text("更多组件4"),
                      Text("更多组件5"),
                      Text("更多组件6"),
                    ],
                  ),
                ),
                child! //可选参数 1.不用每次都加载
              ],
            ),
          );
        },
        child: const Column(
          //2.不用每次都加载
          children: [
            Text("1更多组件1"),
            Text("1更多组件2"),
            Text("1更多组件3"),
            Text("1更多组件4"),
            Text("1更多组件5"),
          ],
        ),
      ),
    );
  }
}
Selector
Selector类和Consumer类似,只是对build调用Widget方法时提供更精细的控制,简单点来说,Selector也是一个消费者,它允许你可以从模型中准备定义哪些属性;Selector 是一个高级的组件,也用于消费共享数据并构建 UI。它接收一个 BuildContext 对象、一个 selector 函数和一个 builder 函数作为参数。selector 函数用于选择需要依赖的共享数据,当且仅当 selector 函数返回的数据发生变化时,Selector 才会重新构建 UI。这可以有效地避免不必要的重建,提高性能。
比如,用户模型中有50个属性,但是我只需要更新年龄,这样我希望不需要重建用户名、电话号码等组件;
模型
class UserModel6 with ChangeNotifier {
  String name = "Jimi";
  int age = 18;
  String phone = "18888888888";
  void increaseAge() {
    age++;
    notifyListeners(); //通知注册的监听器
  }
}
入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});
  @override
  Widget build(BuildContext context) {
return ChangeNotifierProvider(
  create: (_) => UserModel6(),
  child: MaterialApp(
    debugShowCheckedModeBanner: false,
    home: SelectorExample(),
  ),
);
  }
}
使用
class SelectorExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("SelectorExample"),
      ),
      body: Center(
        child: Selector<UserModel6, int>(
          selector: (_, userModel6) => userModel6.age,
          builder: (_, age, child) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(age.toString(),
                    style: const TextStyle(color: Colors.red, fontSize: 30)),
                child!
              ],
            );
          },
          child: Padding(
            padding: EdgeInsets.all(20),
            child: ElevatedButton(
              onPressed: () {
                Provider.of<UserModel6>(context, listen: false).increaseAge();
              },
              child: Text("改变年龄"),
            ),
          ),
        ),
      ),
    );
  }
}
InheritedContext
InheritedContext 是 Provider 内部使用的一个类,用于在 Widget 树中传递共享数据的上下文。在 Provider 中,它被优化为一个轻量级的实现。通常情况下,我们不需要直接使用 InheritedContext。
三大方式:
BuildContext.read:
BuildContext.read<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),它会找到CountNotifier1并返回它。
class InheritedContextExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("InheritedContextExample"),
      ),
      /// read 获取值
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(context.read<CountNotifier2>().count.toString(),
              style: TextStyle(
                  color: Colors.red,
                  fontSize: 50
              ),
            ),
            Padding(
              padding: EdgeInsets.only(top: 20),
              child: ElevatedButton(
                onPressed: () => Provider.of<CountNotifier2>(context, listen: false).increment(),
                child: Text("点击加1"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
BuildContext.watch:
BuildContext.watch<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),看起来和read没有什么不同,但是使用watch你就不需要在使用Consumer。
class InheritedContextExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
         /// 重要(必须)
    final countNotifier2 = context.watch<CountNotifier2>();  
    return Scaffold(
      appBar: AppBar(
        title: Text("InheritedContextExample"),
      ),
      /// watch
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(countNotifier2.count.toString(),
              style: TextStyle(
                  color: Colors.red,
                  fontSize: 50
              ),
            ),
            Padding(
              padding: EdgeInsets.only(top: 20),
              child: ElevatedButton(
                onPressed: () => countNotifier2.increment(),
                child: Text("点击加1"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
BuildContext.select:
BuildContext.select<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),看起来和watch也没有什么不同,但是使用select你就不需要在使用Selector。
class InheritedContextExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// 重要
    final count = context.select((CountNotifier2 countNotifier2) => countNotifier2.count);
    return Scaffold(
      appBar: AppBar(
        title: Text("InheritedContextExample"),
      ),
      /// select
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(count.toString(),
              style: TextStyle(
                  color: Colors.red,
                  fontSize: 50
              ),
            ),
            Padding(
              padding: EdgeInsets.only(top: 20),
              child: ElevatedButton(
                onPressed: () => Provider.of<CountNotifier2>(context, listen: false).increment(),
                child: Text("点击加1"),
              ),
            )
          ],
        ),
      ),
    );
  }
}
参考于 Flutter Provider状态管理---四种消费者使用分析 | Jimi (liujunmin.com)
Provider 四种消费者的更多相关文章
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (一) —— 总览
		Android数据的四种存储方式SharedPreferences.SQLite.Content Provider和File (一) —— 总览 作为一个完成的应用程序,数据存储操作是必不可少的. ... 
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File
		作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别 是:SharePreference.SQLite.Content Provider和File ... 
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (三) —— SharePreferences
		除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息.其存储位置在/data ... 
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (四) —— ContentProvider
		ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制.一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制.并且此种方式忽略了底层的数据存储实现,Cont ... 
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (二) —— SQLite
		SQLite是一种转为嵌入式设备设计的轻型数据库,其只有五种数据类型,分别是: NULL: 空值 INTEGER: 整数 REAL: 浮点数 TEXT: 字符串 BLOB: 大数据 在SQLite中, ... 
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (一)
		作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ... 
- (转)Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (三) —— SharePreferences
		除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息.其存储位置在/data ... 
- ASP.NET MVC下的四种验证编程方式[续篇]
		在<ASP.NET MVC下的四种验证编程方式>一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式("手工验证"."标注Validation ... 
- MSSQL Server数据库的四种连接方法和sql连接字符串
		MSSQL Server数据库的四种连接方法和sql连接字符串 分类: [ 03 ] C#(131) [ 07 ] SQL Server(68) [ 01 ] .NET(189) 今天用SQL Ser ... 
- JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)
		1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ... 
随机推荐
- win10系统单独编译和使用WebRTC的回声消除(AEC)、音频增益(AGC)、去噪(NS)模块
			一.简介 本人想单独编译并使用WebRTC的音频回声消除模块,奈何技术有限,于是在百度的海洋里大海捞针,发现了https://www.cnblogs.com/mod109/p/5827918.html ... 
- Java面向对象编程的三大特性:封装、继承、多态。
			一.封装 封装的核心在于私有化(private),大部分情况下,来封装对象的属性,很少有封装方法的.通过将对象的属性封装,提供对外的公共方法来访问属性是最常见的方式. public static cl ... 
- C/C++中的ACM题目输入处理——简单易上手
			这里就不按其他文章的以各种情况为分类方法,而是以方法本身为分类办法.因为有一些方法是不同情况通用的,比如已知数量数字的输入和未知数量数字的输入,其实可以用同一种办法. 输入 C/C++ :scanf正 ... 
- LVS+keepalived结合
			LVS+Keepalived实现高可用负载均衡(web集群) LVS+Keepalived架构图: 测试环境: 名称 操作系统 IP地址 LVS-MASTER Centos7.x 192.168. ... 
- 文心一言 VS 讯飞星火 VS chatgpt (121)-- 算法导论10.4 2题
			二.用go语言,给定一个n结点的二叉树,写出一个 O(n)时间的递归过程,将该树每个结点的关键字输出. 文心一言: 在Go语言中,你可以使用递归函数来遍历二叉树的所有节点,并输出每个节点的关键字.以下 ... 
- meet
			以后就放弃csdn了,就来这里记录自己的成长,就当成一个树洞吧,开心与难过,学习与生活,进步与成长,留下时间的痕迹!冲!冲!冲! 
- QT中级(2)QTableView自定义委托(二)实现QProgressBar委托
			同系列文章 QT中级(1)QTableView自定义委托(一)实现QSpinBox.QDoubleSpinBox委托 QT中级(2)QTableView自定义委托(二)实现QProgressBar委托 ... 
- URL, URI 和 URN 之间的区别
			英文原文:What's the difference between a URI and a URL? URI 标识一个事物 , URL 定位一个事物:然而,位置同样可以标识一个事物,所以,每个 U ... 
- CSS 单行/多行文本溢出显示省略号(...)的实现
			作者:WangMin 格言:努力做好自己喜欢的每一件事 我们在项目开发的过程中也许都遇到过这样的问题:我们需要实现这样一个需求,在一个父级元素中隐藏一个可能过长的文本.而这个需求可以分解为两个,一个是 ... 
- 基于C# Socket实现的简单的Redis客户端
			前言 Redis是一款强大的高性能键值存储数据库,也是目前NOSQL中最流行比较流行的一款数据库,它在广泛的应用场景中扮演着至关重要的角色,包括但不限于缓存.消息队列.会话存储等.在本文中,我们将介绍 ... 
