• provider 跨组件状态管理


    provider 跨组件状态管理

    Provider 包是由 Remi Rousselet 创建旨在尽可能快速地处理状态。在 Provider 中,小部件会监听状态的变化,并在收到通知后立即更新。

    因此,当有状态改变时,而不是重建整个 widget 树,只改变受影响的 widget,从而减少工作量并使应用程序运行得更快更流畅。

    一、原理

    Model变化后会自动通知ChangeNotifierProvider(订阅者),ChangeNotifierProvider内部会重新构建InheritedWidget,而依赖该InheritedWidget的子孙Widget就会更新。

    原有普遍方式:通过参数传递数据,并setState实时更新组建;

    使用Provider益处:

      1. 业务代码更关注数据,只要更新Model,则UI会自动更新,而不用在状态改变后再去手动调用setState()来显式更新页面。

      2. 数据改变的消息传递被屏蔽了,我们无需手动去处理状态改变事件的发布和订阅了,这一切都被封装在Provider中了。这真的很棒,帮我们省掉了大量的工作!

      3. 在大型复杂应用中,尤其是需要全局共享的状态非常多时,使用Provider将会大大简化我们的代码逻辑,降低出错的概率,提高开发效率。

    二、状态管理方式

    1、Provider 方式

    provider 不需要被监听,有的常量或者方法,根本不需要“牵一发而动全身”,也就是说他们不会被要求随着变动而变动,这样的需求使用Provider;

    最基本的状态管理方式,以一个参数方式绑定和展示;

    1) 绑定单条数据

    Provider 可在需要的 Widget 处进行数据绑定;

    基本单条数据绑定:

    当我们确定绑定的数据类型时,建议绑定时添加数据类型,如:Provider<String>.value( value: '', child:);不确定类型Provider.value( value: '', child:)

    Column(
        children: [
            Provider<String>.value( value: 'Provider 基础传值', child: const BaseValueWidget()),
        ],
    ) 

    2)获取数据

    class BaseValueWidget extends StatelessWidget {
      const BaseValueWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Text(Provider.of<String>(context));
      }
    }
    

     3)绑定多条数据

     Column(
      children: [
        /// 单条传值
        Provider<String>.value(
            value: 'Provider 基础传值', child: const BaseValueWidget()),
    
        /// 多条传值 UserModel实体
        //嵌套绑定
        Provider<UserModel>.value(
            value: UserModel('嵌套绑定', 18),
            child: Provider<int>.value(
                value: 20,
                child: Provider<bool>.value(
                    value: false, child: const NestingWidget()))),
        // 聚合方式 推荐
        MultiProvider(providers: [
          Provider<UserModel>.value(value: UserModel('聚合方式', 10)),
          Provider<int>.value(value: 11),
          Provider<bool>.value(value: false)
        ], child: const NestingWidget()),
      ],
    )
    
    class UserModel {
      String name;
      int age;
      UserModel(this.name, this.age);
    }

    获取数据

    class NestingWidget extends StatelessWidget {
      const NestingWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Text(
            'Provider: '
            '${Provider.of<int>(context)} | ${Provider.of<bool>(context)} | ${Provider.of<UserModel>(context).name} |${Provider.of<UserModel>(context).name = 'Hello World!'}',
            style: const TextStyle(color: Colors.redAccent));
      }
    }
    Provider 绑定数据类型比较灵活,并非只是基本数据类型,这里定义了一个 UserModel 类,可正常状态管理;获取 name 后重新设置 name 之后获取的 UserModel 为最新的数据;

    4)作用域

    获取绑定数据的范围是在绑定数据的子 Widget 中;

    2、ChangeNotifierProvider 方式

    ChangeNotifierProvider 它会随着某些数据改变而被通知更新,也就是说,比如这个 Model 被用在多个 page,那么当其中一处被改变时,他就应该告诉其他的地方,改更新了,这样的需求就使用ChangeNotifierProvider;

    通过调用 ChangeNotifier.notifyListenersChangeNotifier 进行监听,将其公开给它的子 Widget 并重建依赖项;

    1) 绑定数据

    ChangeNotifierProvider 绑定数据有两种方式:
    ChangeNotifierProvider({Key key, @required ValueBuilder builder, Widget child });通过构造器创建一个 ChangeNotifier,在 ChangeNotifierProvider 移除时自动处理;
    ChangeNotifierProvider(
      create: (_) => PersonChangeNotifier('ChangeNotifier方式1', 11),
      child: const NotifierWidget(),
    ),
    ChangeNotifierProvider.value({Key key, @required T notifier, Widget child }) 通过监听通知给子 Widget 并重建依赖项;
    ChangeNotifierProvider<PersonChangeNotifier>.value(
      value: PersonChangeNotifier('ChangeNotifier方式2', 1),
      child: const NotifierWidget(),
    )
    
    class PersonChangeNotifier with ChangeNotifier {
      String name;
      int age;
      PersonChangeNotifier(this.name, this.age);
      updateName(String name) {
        this.name = name;
        notifyListeners();
      }
    }

    2) 获取数据

    获取数据的方式与直接使用 Provider 相似;

    Text(Provider.of<PersonChangeNotifier>(context).name);

    相对于 ProviderChangeNotifierProvider 方式更加灵活,可以通过重写 get/set 方法来对状态管理进行修改和使用;

    3)更新数据

    class NotifierWidget extends StatelessWidget {
      const NotifierWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Text(Provider.of<PersonChangeNotifier>(context).name),
            InkWell(
              child: const Text('点击更新name'),
              onTap: () {
                context.read<PersonChangeNotifier>().updateName('name');
              },
            ),
          ],
        );
      }
    }

    3、ChangeNotifierProxyProvider

    ChangeNotifierProxyProvider 它不仅要像ChangeNotifierProvider一样,通知更新,还要协调 Model 与 Model 之间的更新,比如一个 ModelA 依赖另一个 ModelB,ModelB 更新,他就要让依赖它的 ModelA 也随之更新,这就是使用ChangeNotifierProxyProvider;
    https://pub.flutter-io.cn/documentation/provider/latest/provider/ChangeNotifierProxyProvider-class.html
    ChangeNotifierProvider(
      create: (context) {
        return MyChangeNotifier(
          myModel: Provider.of<MyModel>(context, listen: false),
        );
      },
      child: ...
    )
    

    三、有选择地更新状态

    该Consumer控件只允许子控件,而不在 widget 树影响其他部件重建,小部件进行更新。

    我们通过Text用 a 包装两个小部件ColumnbuilderConsumer小部件公开的函数处返回它来实现这一点:

     
    Consumer<UserDetailsProvider>(
      builder: (context, provider, child) {
        return Column(
          children: [
            Text(
              'Hi ' + provider.name,
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            Text(
              'You are ' + provider.age.toString() + ' years old',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w400,
              ),
            ),
          ],
        );
      },
    )
    
  • 相关阅读:
    php 内置的 webserver 研究。
    php 系列
    git 以及 github 使用系列
    中午和同事聊天,了解的一点网络方面的东西。
    javascript中0.01*2324=23.240000000000002 ?
    javascript的 replace() 方法的使用讲解
    PHP中的ORM
    javascript 函数 add(1)(2)(3)(4)实现无限极累加 —— 一步一步原理解析
    animate.css
    面向对象编程
  • 原文地址:https://www.cnblogs.com/lulushen/p/16090992.html
Copyright © 2020-2023  润新知