Flutter Provider 共享状态管理

在使用Provider的时候,我们主要关心三个概念:

  • ChangeNotifier:真正数据(状态)存放的地方
  • ChangeNotifierProvider:Widget树中提供数据(状态)的地方,会在其中创建对应的ChangeNotifier
  • Consumer:Widget树中需要使用数据(状态)的地方

前提条件:

使用之前,我们需要先引入对它的依赖,截止这篇文章,Provider的最新版本为6.0.4:

dart 复制代码
dependencies:
  provider:^4.0.4

第一步:创建自己的ChangeNotifier

(这里可以对每个需要共享的数据创建自己的文件进行管理)

dart 复制代码
/**
 * 使用继承自ChangeNotifier,也可以使用混入,这里取决于是否需要已经继承了其他的类
 * 创建一个私有的 _counter,并且提供get set方法
 * 在set方法中监听 _counter的改变,如果改变就调用 notifyListeners方法、通知所有的Consumer进行更新
 */
class CounterProvider extends ChangeNotifier {
  int _counter = 100;
  int get counter => _counter;
  set counter(int value) {
    _counter = value;
    notifyListeners(); // 通知所有的Consumer进行更新
  }
}
dart 复制代码
import'package:flutter/material.dart';

class UserInfo {
  String nickname;
  int level;
  UserInfo(this.nickname, this.level);
}

class UserProvider extends ChangeNotifier {
  UserInfo _userInfo = UserInfo("why", 18);

  set userInfo(UserInfo info){
    _userInfo = info;
    notifyListeners();
  }

  get userinfo{
    return _userInfo;
  }

}

第二步:在Widget Tree中插入ChangeNotifierProvider

dart 复制代码
void main() {
  runApp(
    // ChangeNotifierProvider 放到顶层,这样方便在整个应用的任何地方可以使用 CounterProvider
    MultiProvider(providers: [
      // 存放多个共享数据
      ChangeNotifierProvider(create: (ctx)=> CounterProvider()),
      ChangeNotifierProvider(create: (ctx) => UserProvider())
    ],
      child: MyApp(),
    ),
  );
}

第三步:在首页中使用Consumer引入和修改状态

(这里使用了Selector 替换了Consumer进行了优化 )

dart 复制代码
class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 脚手架
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column (
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            HYShowData01(),
            HYShowData02(),
          ],
        ),
      ),
      floatingActionButton: Selector<CounterProvider,CounterProvider> (
        // 某种情况下使用 Selector代替Consumer,性能会更高
        selector: (ctx,provider) => provider,
        shouldRebuild: (pre, next) => false,// 是否需要重新 build
        builder: (ctx, counterPro,child) {
          print("floatingActionButton 展示位置builder被调用");
          return FloatingActionButton(
              child: child,
              onPressed: () {
            counterPro.counter +=1;
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}


class HYShowData01 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("HYShowData01");
    return Consumer<CounterProvider>(
      builder: (ctx, counterPro, child) {
        // ctx: 每个build 方法都会有上下文,目的是知道当前树的位置
        // counterPro:对应的实例,也是我们在builder函数中主要使用的对象
        // child: 目的是进行优化,如果builder下面有一颗庞大的子树,当模型发生改变的时候,我们并不希望重新build这颗子树,那么就可以将这颗子树放到Consumer的child中,在这里直接引用即可
        print("HYShowData011");
        return Text("共享状态:${counterPro.counter}");
      },

    );
  }
}

class HYShowData02 extends StatefulWidget {
  @override
  State<HYShowData02> createState() => _HYShowData02State();
}

class _HYShowData02State extends State<HYShowData02> {
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    // 使用Consumer 是为了尽可能少的 rebuild widget
    // 当我们点击了 FloatingActionButton时,HomePage的build方法会被重新调用,这意味着HomePage的widget的widget都需要重新build
    // 使用Consumer 会发现 Homepage的build方法不会被重新调用
    print("_HYShowData02State");
    return Consumer<CounterProvider>(builder: (ctx, counterPro,child) {
      print("_HYShowData022State");
      return Text("共享状态:${counterPro.counter}");
    });
  }
}
相关推荐
微学AI8 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
豆瓣鸡8 小时前
算法日记 - Day3
java·开发语言·算法
夏殇之殁9 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
韭菜炒鸡肝天9 小时前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt
Aaron - Wistron10 小时前
Web API C# (Furion版)带 单元测试
开发语言·后端·c#
新中地GIS开发老师10 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
蜡台10 小时前
Flutter 环境搭建 Dart配置
flutter·dart
丙氨酸長鏈10 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
Dxy123931021610 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
05664611 小时前
Python康复训练——常用标准库
开发语言·python·学习