Flutter的状态管理之Provider

前言

像vue、react有对应的状态管理库,比如:piniaRedux 。同样flutter中也有状态管理库,但是flutter中的状态管理库很多,对于像我这样的新手来说这很难选择。因此只好选择官方库——Provider

因为是第一次学习,如果有哪些地方理解的不正确,麻烦指出。

参考:

官方文档

Provider

简介

Provider是一个Flutter状态管理库,它是基于InheritedWidget的简单、可扩展且易于使用的解决方案。它帮助开发者在Flutter应用程序中管理和共享状态,以便于组件之间的通信和数据共享。

Provider的核心概念是"Provider"和"Consumer"。Provider是一个数据源,它包含要共享的数据,并将其提供给应用程序中的其他组件。Consumer是一个接收Provider数据的组件,它会自动订阅Provider,并在数据发生变化时进行更新。

使用Provider,开发者可以避免在组件树中手动传递数据。相反,它提供了一种便捷的方式来访问和更新共享数据。开发者只需要在应用程序的根部分创建一个Provider,并在需要访问共享数据的组件中使用Consumer来获取数据。

Provider还提供了一些高级功能,如多Provider的组合、跨组件的数据传递、数据变更通知、异步数据处理等。它还支持与其他状态管理库(如Redux)的集成,以满足更复杂的应用程序需求。

这里的话,我们只学习最基础的部分。高级功能等水平达到后,再学习

基本使用

安装

flutter pub add provider

我们以数字新增为例

1、创建一个状态管理类

首先需要创建一个状态管理类,对于需要共享的状态进行统一管理

counter_state.dart

import 'package:flutter/cupertino.dart';// 创建状态管理类
class CounterState with ChangeNotifier {
//   要共享的状态int _count = 0;// 获取状态int get count => _count;// 修改状态的方法void increment() {_count++;//  通知使用该状态的widgetnotifyListeners();}
}

注意点:

  • 在Flutter项目中,通常使用小写字母和下划线来命名源代码文件
  • 状态建议定义为私有类型(变量前面加_),不要直接修改状态
  • 使用混合模式,而不是使用继承。避免继承关系的复杂性

2、创建顶层共享数据

//使用箭头函数简写
main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {//创建widget的唯一标识const MyApp({Key? key}) : super(key: key);//重写build方法Widget build(BuildContext context) {// ChangeNotifierProvider 会返回一个 ChangeNotifier 对象,它允许消费者在 CounterState 对象发生变化时收到通知。return ChangeNotifierProvider(// CounterState 对象会作为共享的状态实例被整个应用程序使用。create: (context) => CounterState(),child: const MaterialApp(home: YcHomePage(),),);}
}

或者

runApp(ChangeNotifierProvider(create: (context) => CounterState(),child: const MyApp(),
));

本质上是通过ChangeNotifierProvider来为最父级的widget来提供状态

3、在子页面中使用

//app的主页面
class YcHomePage extends StatelessWidget {const YcHomePage({Key? key}) : super(key: key);Widget build(BuildContext context) {// 从上下文中获取类型为 CounterState 的对象final counter = Provider.of<CounterState>(context);return Scaffold(appBar: AppBar(title: const Text('Provider状态管理'),),body: Center(child: Column(children: [// 调用get方法获取值Text("数值是:${counter.count}"),// 用于占位const SizedBox(height: 30,),ElevatedButton(onPressed: () {//  调用increment方法counter.increment();},child: const Text("加1"))],)),);}
}

注意点:
避免产生副作用,我们在build方法里通过 final counter = Provider.of<CounterState>(context);来获取实例。这里需要注意不要在build方法里执行一些操作,比如数据请求。原因是:调用Provider.of<T>(context); 会重新运行其 build方法,这会导致build里面的某些操作又被执行了一次。,这就是副作用

解决方式是在initState方法里来执行这些操作,initState 只会在初始化的时候被执行。

或者

class YcHomePage extends StatelessWidget {const YcHomePage({Key? key}) : super(key: key);Widget build(BuildContext context) {// 掉接口获取数据,或者其他的操作return Scaffold(appBar: AppBar(title: const Text('Provider状态管理'),),body: Center(child: Consumer<CounterState>(builder: (context,counterState,child){return Column(children: [// 调用get方法获取值Text("数值是:${counterState.count}"),// 用于占位const SizedBox(height: 30,),ElevatedButton(onPressed: () {//  调用increment方法counterState.increment();},child: const Text("加1"))],);})));}
}

这种方式是通过Consumer来创建一个消费者,然后在builder函数中通过上下文参数(context)来获取CounterState对象。这样做的优点是可以直接在builder函数中访问CounterState对象,并且可以在builder函数中进行一些额外的逻辑处理。

这种方式下,在build里执行的操作不会在状态更新后再次执行。但是在builder中的话,当状态更新后每次都会执行。这里可以自己使用print打印一下日志试试。

局部使用

局部使用与全局使用很相似,假设有两个子组件需要共享某个状态,这时你可以在这两个子组件的公共父组件上使用ChangeNotifierProvider来提供状态。

多个 Provider

如果需要共享的状态不多时,使用一个状态管理类是没有问题的。但是当状态过多时,都放在一个状态管理类里是不合适。这时应该建立不同的状态类,来管理不同类别的状态。这时后可以结合MultiProvider

main() {runApp(MultiProvider(providers: [ChangeNotifierProvider<CounterState>(create: (context) => CounterState()),//  其他的状态],child: const MyApp(),));
}

关于获取到对应的状态实例,你可以使用final counter = Provider.of<CounterState>(context);,也可以使用
Consumer<CounterState>(builder: (context, counterState, child) {} ,唯一需要注意的是类型不要填写错误了。

其他类型的Provider

上面的例子中使用的都是ChangeNotifierProvider,除了ChangeNotifierProvider还有其他的Provider

ListenableProvider:

  • ListenableProvider是Flutter中的一种Provider,用于将依赖项注入到需要监听列表数据变化的组件中。
  • 当依赖项发生变化时,ListenableProvider会通知所有订阅者(subscribers)更新他们的UI。
  • 适合在需要监听列表数据变化的情况下使用,例如在列表视图中显示动态数据时,可以使用ListenableProvider来管理数据并提供数据变化的通知。

ChangeNotifierProvider:

  • ChangeNotifierProvider是Dart语言中另一个用于实现依赖注入的Provider类,它主要用于管理可变数据并提供数据变化的通知。
  • 当依赖项发生变化时,ChangeNotifierProvider会通知所有订阅者(subscribers)更新他们的UI。
  • 适合在需要管理可变数据并提供数据变化通知的情况下使用,例如在应用程序中管理用户设置或配置信息时,可以使用ChangeNotifierProvider来提供数据变化通知并更新相关UI。

ValueListenableProvider:

  • ValueListenableProvider是Flutter中的一种Provider类,用于将依赖项注入到需要监听单个值变化或状态改变的组件中。
  • 当依赖项发生变化时,ValueListenableProvider会通知所有订阅者(subscribers)更新他们的UI。
  • 适合在需要监听单个值或状态改变的情况下使用,例如在应用程序中管理用户状态或设置时,可以使用ValueListenableProvider来提供值变化通知并更新相关UI。

StreamProvider:

  • StreamProvider是Dart语言中的一种Provider类,用于将依赖项注入到需要监听流数据变化的组件中。
  • 当依赖项发生变化时,StreamProvider会通知所有订阅者(subscribers)更新他们的UI。
  • 适合在需要监听流数据变化的情况下使用,例如在实时更新数据流的情况下,可以使用StreamProvider来管理流数据并提供数据变化的通知。

下面简单看一个ListenableProvider,其他略,可自行百度

创建自定义状态类

class ListDataState with ChangeNotifier {List<String> _listData = [];List<String> get listData => _listData;void addItem(String item) {_listData.add(item);notifyListeners();}void removeItem(String item) {_listData.remove(item);notifyListeners();}
}

使用

Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('列表数据状态管理'),),body: Consumer<ListDataState>(builder: (context, listDataState, child) {return ListView.builder(itemCount: listDataState.listData.length,itemBuilder: (context, index) {final item = listDataState.listData[index];return ListTile(title: Text(item),onTap: () {listDataState.removeItem(item);},);},);},),floatingActionButton: FloatingActionButton(onPressed: () {Provider.of<ListDataState>(context, listen: false).addItem('New Item');},child: Icon(Icons.add),),);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2watch监听遇到的问题

1 vue 父组件里引入子组件 显示与隐藏是v-if控制时 父传入子的参数通过watch 监听请求接口时 watch 时而监听不到 请求接口的参数就不对 如图 父组件这么引入子组件v-show 和v-if 是有区别的 2 子组件通过watch 监听后 清空页面要展示的列表数据 重新从第一页加载数据&#x…

扶小微、惠民生,平安养老险护航中小企业健康发展

今年以来&#xff0c;随着经济社会全面恢复常态化运行&#xff0c;稳增长、稳就业、稳物价政策效应逐步显现&#xff0c;市场需求逐步恢复&#xff0c;生产供给持续增加&#xff0c;我国经济发展质量继续提高&#xff0c;国民经济恢复向好。平安养老险作为平安集团内专业养老保…

【雕爷学编程】Arduino动手做(164)---Futaba S3003舵机模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

log4j复现之CVE-2017-5645

log4j复现之CVE-2017-5645 一、靶机环境的安装 1.docker环境安装 apt-get update apt-get install -y apt-transport-https ca-certificates apt install docker.io apt-get install python3-pip pip3 install docker-compose docker-compose -v2.下载vlnhub git clone …

长沙打造“全球研发中心城市”,智能网联产业如何交卷?

作者 | 魏启扬 来源 | 洞见新研社 知乎上有一个浏览超百万的热门问题——“大家怎么看待长沙这个城市&#xff1f;” 答主“星球研究所”的回答获得了高赞&#xff0c;“这是一个天性如火的城市”。 网红城市的外衣下&#xff0c;从湖南卫视的综艺节目&#xff0c;到网红美…

qiankun:react18主应用 + 微应用 react18 + vue3

一&#xff1a;主应用 搭建react项目 npx create-react-app react-qiankun-main安装Antd npm install antd –save在 index.js中引入 import { ConfigProvider } from "antd"; import zhCN from "antd/locale/zh_CN"; import "antd/dist/reset.css…

Redis PipelineScript

文章目录 前言一、Pipeline是什么&#xff1f;二、Pipeline具体实现特点缺点 三、ScriptScript具体实现对比Pipeline三、总结 前言 玩过远程过程调用的小伙伴都知道&#xff0c;一次请求多条数据要比多次请求1条数据效率高&#xff08;当然&#xff0c;这里的多条数据通常是完…

DDOS百科:什么是 DDoS 攻击及如何防护DDOS攻击

一、什么是 DDoS 攻击&#xff1f; 当多台机器一起攻击一个目标&#xff0c;通过大量互联网流量淹没目标或其周围基础设施&#xff0c;从而破坏目标服务器、服务或网络的正常流量时&#xff0c;就会发生分布式拒绝服务(DDoS)攻击。 DDoS允许向目标发送指数级更多的请求&#…

【大数据之Hadoop】三十七、Hadoop HA高可用

1、HA概述 实现高可用最关键的策略是消除单点故障。HA分成各个组件的HA机制&#xff1a;HDFS的HA和YARN的HA。   Hadoop2.0之前&#xff0c;在HDFS集群中NameNode存在单点故障&#xff08;SPOF&#xff09;。 NameNode主要在以下两个方面影响HDFS集群&#xff1a; &#xff…

AI时代图像安全“黑科技”如何助力人工智能与科技发展?

〇、前言 7月7日下午&#xff0c;2023世界人工智能大会&#xff08;WAIC&#xff09;“聚焦大模型时代AIGC新浪潮—可信AI”论坛在上海世博中心红厅举行。人工智能等技术前沿领域的著名专家与学者、投资人和领军创业者汇聚一堂&#xff0c;共同探索中国科技创新的驱动力量。 在…

4. 设计(黑盒)测试用例 (一) 等价类 边界值 判定表

本篇文章我们将详细介绍如何来测试用例。 1. 设计测试用例的基本要素 1.1 测试用例概念 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合。 1.2 测试用例要素 测试环境、测试步骤、测试数据、预期结果。 1.3 测试用例的重要性 提…

【美团面试】软件测试面试题

一、设计登录界面测试用例 功能测试(Function test) 0. 什么都不输入&#xff0c;点击提交按钮&#xff0c;看提示信息。&#xff08;非空检查&#xff09; 1.输入正确的用户名和密码&#xff0c;点击提交按钮&#xff0c;验证是否能正确登录。&#xff08;正常输入&#xff0…

【启发式算法】灰狼优化算法【附python实现代码】

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 路虽远&#xff0c;行则将至&#…

江南大学轴承数据故障诊断(利用连续小波变换转换为二维图像,再利用CNN进行故障诊断)

1.江南大学轴承数据集介绍 采样频率&#xff1a;50khz&#xff0c;采样时间&#xff1a;10s 转速&#xff1a;600 800 1000/rpm 内圈&#xff1a;ib 外圈&#xff1a;ob 滚动体&#xff1a;tb 正常&#xff1a;N 以600转速下的内圈故障数据为例展示&#xff1a; 开始数据…

第46节:cesium 水面效果(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><!

C 知识积累 替换gets函数 Linux C 语法分析 switch和if else的比较

目录 替换gets函数gets()用处gets()的危险之处gets()的几种替代方法一、用%c循环输入直到遇到换行结束二、用getchar()循环输入直到遇到换行结束三、scanf的另一种用法四、c中的getline()方法五、解决方案使用fgets代替 回车与换行一.知其然二.知其所以然 关键字&#xff0c;操…

怎样优雅地增删查改(五):按组织架构查询

文章目录 原理实现应用测试 之前我们实现了Employee&#xff0c;Alarm管理模块以及通用查询应用层。 Employee的集合查询业务&#xff0c;是通过重写CreateFilteredQueryAsync方法&#xff0c;来实现按组织架构查询的过滤条件。 我们将这段逻辑代码提取到通用查询应用层中&…

Web开发的富文本编辑器CKEditor介绍,Django有库ckeditor_uploader对它进行支持

当需要在网页应用程序中提供富文本编辑功能时&#xff0c;CKEditor是一个流行的选择。CKEditor是一个开源的JavaScript富文本编辑器&#xff0c;它提供了强大的功能和用户友好的界面&#xff0c;使用户可以轻松创建和编辑格式化的文本内容。 以下是CKEditor的一些主要特性&…

大厂sql真题讲解(黑马)

2023 http://yun.itheima.com/open/853.html | 面试宝典-如何备战大厂SQL真题 http://yun.itheima.com/open/858.html | 面试宝典–大厂必考知识开窗函数 http://yun.itheima.com/open/864.html | 面试宝典-详解美团SQL真题 http://yun.itheima.com/open/868.html | 图解大…

【技巧】动态执行js脚本

【技巧】动态执行js脚本 我们写的 js 代码&#xff0c;主要执行在浏览器环境和 node 环境&#xff0c;也叫宿主环境。宿主环境通过加载机制获取到我们的代码&#xff0c;然后使用 js 引擎解释执行。这是正常的 js 代码执行流程。有些场景下&#xff0c;js 代码是通过程序动态生…