ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

provider 跨组件状态管理

2022-04-02 11:03:06  阅读:244  来源: 互联网

标签:状态 child name provider value context Provider 组件 ChangeNotifierProvider


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,
          ),
        ),
      ],
    );
  },
)

 

标签:状态,child,name,provider,value,context,Provider,组件,ChangeNotifierProvider
来源: https://www.cnblogs.com/lulushen/p/16090992.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有