Code前端首页关于Code前端联系我们

Flutter Provider 3.0 状态管理教程

terry 2年前 (2023-09-23) 阅读数 67 #移动小程序

provider 是 Google I/O 2019 大会上宣布的目前官方推荐的状态管理方法。 provider,语法糖是InheritedWidget,它允许在widget树中传递数据,让我们可以更灵活的处理数据类型和数据。

项目地址

flutter_provider 本教程的项目源码,欢迎star

为什么需要状态管理

在开发项目时,我们经常需要管理不同页面之间的数据共享。当页面功能复杂,状态达到几十上百的时候,我们就很难清晰的维护自己的数据状态。本文将用状态管理配合简单的计数器功能来讲解如何在 Flutter 中使用 provider 的状态管理框架

为什么选择 Provider

上次给大家介绍过 provide,然后 provide 就被抛弃了。不过,从provide转向provider的学习成本并不高。要理解provide,可以切换到Flutter UI,使用Provide来切换主题数据变化,会进行页面级重建,相当于stfulWidget

  • 使用consumer,consumer优于provider。 of(context) 有点复杂,但它对提高应用程序性能有一些不错的效果。当状态改变时,widget树会更新指定的节点并且控件会进行最小程度的更新,整个widget树不会更新。 ,具体请看下面的分析。
  • 提供者具有泛型的优势,它对应于命名空间的属性。用过vuex的应该都知道namespace的重要性。它分隔了我们的状态
  • 项目地址

    flutter-provide r,可以参考项目中使用provide r方法

    效果

    Flutter Provider 3.0状态管理实战教程Flutter Provider 3.0状态管理实战教程

    如何使用pubber添加-install
    • 介绍pubspec.yaml 中的依赖项
    dependencies:
          provider: 3.0.0+1 #数据管理层
    复制代码
    • 在要使用的页面执行
    flutter packages get
    复制代码
    • 引入
    import 'package:provider/provider.dart'
    复制代码

    创建模型(这是第一步)
    dependencies:
          provider: 3.0.0+1 #数据管理层
    复制代码
    • 创建 /CounterInfo.dart 文件

      创建新的 lib / store/object/UserInfo.dart 文件

      数据模型,我不想插入它 代码已经出来

      创建一个新的 lib/store/model/CounterModel。 dart 文件

      import 'package:flutter/foundation.dart' show ChangeNotifier;
      import '../object/CounterInfo.dart';
      export '../object/CounterInfo.dart';
      
      class Counter extends CounterInfo with ChangeNotifier {
        CounterInfo _counterInfo = CounterInfo(count: 0, totalInfo: TotalInfo(total: 2));
      
        int get count => _counterInfo.count;
        TotalInfo get totalInfo => _counterInfo.totalInfo;
      
        void increment () {
          _counterInfo.count++;
          notifyListeners();
        }
      
        void decrement () {
          _counterInfo.count--;
          notifyListeners();
        }
      }
      复制代码

      新建一个 lib/store/model/UserModelModel.dart 文件

      import 'package:flutter/foundation.dart' show ChangeNotifier;
      import '../object/UserInfo.dart';
      export '../object/UserInfo.dart';
      
      class UserModel extends UserInfo with ChangeNotifier {
        UserInfo _userInfo = UserInfo(name: '咕噜猫不吃猫粮不吃鱼');
      
        String get name => _userInfo.name;
      
        void setName (name) {
          _userInfo.name = name;
          notifyListeners();
        }
      }
      复制代码

      通过 mixin 混入 ChangeNotifier,并通过 notificationListeners 通知监听器进行更新

      是的,我们已经差不多完成了 store 的封装。所有步骤都在这里)

      新建lib/store/index.dart文件

      import 'package:flutter/material.dart' show BuildContext;
      import 'package:provider/provider.dart'
        show ChangeNotifierProvider, MultiProvider, Consumer, Provider;
      import 'model/index.dart' show Counter, UserModel;
      export 'model/index.dart';
      export 'package:provider/provider.dart';
      
      class Store {
        static BuildContext context;
        static BuildContext widgetCtx;
      
        //  我们将会在main.dart中runAPP实例化init
        static init({context, child}) {
          return MultiProvider(
            providers: [
              ChangeNotifierProvider(builder: (_) => Counter()),
              ChangeNotifierProvider(builder: (_) => UserModel(),)
            ],
            child: child,
          );
        }
      
        //  通过Provider.value<T>(context)获取状态数据
        static T value<T>(context) {
          return Provider.of(context);
        }
      
        //  通过Consumer获取状态数据
        static Consumer connect<T>({builder, child}) {
          return Consumer<T>(builder: builder, child: child);
        }
      }
      
      复制代码

      如果需要管理多种模式,只需要在provide rs中添加对应的模式即可

      provide rs: [ProviderNotifier : (builder: () => Counter()), ChangeNotifierProvider(builder: () => UserModel(),) ],

      定义全局 Give(倒数第二个)❀❝ .dart 文件
      import 'package:flutter/material.dart';
      import 'package:flutter_provider/store/index.dart' show Store;
      import 'package:flutter_provider/page/firstPage.dart' show FirstPage;
      
      void main () {
        runApp(MyApp());
      }
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          print('根部重建: $context');
          return Store.init(
            context: context,
            child: MaterialApp(
              title: 'Provider',
              home: Builder(
                builder: (context) {
                  Store.widgetCtx = context;
                  print('widgetCtx: $context');
                  return FirstPage();
                },
              ),
            )
          );
        }
      }
      复制代码

      创建页面(已完成)

    创建新的 lib/page/firstPage.dart 文件

    import 'package:flutter/material.dart';
    import 'package:flutter_provider/store/index.dart' show Store, Counter, UserModel;
    import 'package:flutter_provider/page/secondPage.dart' show SecondPage;
    
    class FirstPage extends StatelessWidget {
      TextEditingController controller = TextEditingController();
      @override
      Widget build(BuildContext context) {
        print('first page rebuild');
        return Scaffold(
          appBar: AppBar(title: Text('FirstPage'),),
          body: Center(
            child: Column(
              children: <Widget>[
                Store.connect<Counter>(
                  builder: (context, snapshot, child) {
                    return RaisedButton(
                      child: Text('+'),
                      onPressed: () {
                        snapshot.increment();
                      },
                    );
                  }
                ),
                Store.connect<Counter>(
                  builder: (context, snapshot, child) {
                    print('first page counter widget rebuild');
                    return Text(
                      '${snapshot.count}'
                    );
                  }
                ),
                Store.connect<Counter>(
                  builder: (context, snapshot, child) {
                    return RaisedButton(
                      child: Text('-'),
                      onPressed: () {
                        snapshot.decrement();
                      },
                    );
                  }
                ),
                Store.connect<UserModel>(
                  builder: (context, snapshot, child) {
                    print('first page name Widget rebuild');
                    return Text(
                      '${Store.value<UserModel>(context).name}'
                    );
                  }
                ),
                TextField(
                  controller: controller,
                ),
                Store.connect<UserModel>(
                  builder: (context, snapshot, child) {
                    return RaisedButton(
                      child: Text('change name'),
                      onPressed: () {
                        snapshot.setName(controller.text);
                      },
                    );
                  }
                )
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            child: Center(
              child: Icon(Icons.group_work)
            ),
            onPressed: () {
              Navigator.of(context)
                .push(MaterialPageRoute(builder: (BuildContext context) {
                  return SecondPage();
              }));
              // Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) {
              //   return SecondPage();
              // }));
            },
          ),
        );
      }
    }
    复制代码

    创建新的 lib/page/secondPage.dart 文件 所有数据状态都是通过 Consumer 获取的。 firstPage 中使用了两个存储(计数器和用户模型)来绑定两个不同的权重。优点是:

    • 当我用+或-更改数据时,只有使用计数器数据模型的小部件才会通过单击更改名称进行更新当按下按钮时,用户模型中的名称将发生变化,并且只有使用该用户模型的权重才会更新。
    • 按显示数字的比例执行 print('重建首页计数器部件');
    • print('首页名称部件重建');

    结果是重建首页只会是页面初始化时打印。 ,增加或减少操作数据和更改名称只会重现相应的重量。下图是单独更改数据和更改名称后的控制台输出Flutter Provider 3.0状态管理实战教程

    • 另一方面,我通过Provider.value( context )来操作数据,使用起来更加方便简单,但是当数据发生变化时,将发生页面级更新
      • 第二页内置打印('重建第二页');
      • 在显示数字的权重中打印('重建第二页计数器小部件');

    结果是在页面初始化时打印重建第二页,但每当数据发生变化时也会打印Flutter Provider 3.0状态管理实战教程

    综上所述,使用Provider.value(context)会导致页面刷新。虽然 Flutter 会自动优化更新,但还是建议大家尽可能使用 Consumer 来获取数据,以达到最佳的应用性能提升

    作者:YYDev
    链接:https://juejin.im/post/ 5d2c19c6e51d4558936aa11c
    来源:掘金
    版权归作者所有。商业转载请联系作者获取授权。非商业转载请注明出处。

    版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

    热门