当前位置: 首页 > news >正文

3.2 原生方案

Flutter 提供了三种原生(无需第三方依赖)的状态管理方案,分别适用于不同规模和场景。


一、setState:局部状态管理

setState是 Flutter 最基础的状态管理方式,适合管理单个 Widget 内的局部状态。

1.1 基本用法

classShoppingCartButtonextendsStatefulWidget{constShoppingCartButton({super.key});@overrideState<ShoppingCartButton>createState()=>_ShoppingCartButtonState();}class_ShoppingCartButtonStateextendsState<ShoppingCartButton>{int _itemCount=0;bool _isAdding=false;Future<void>_addToCart()async{setState(()=>_isAdding=true);try{awaitCartService.addItem();setState(()=>_itemCount++);}finally{setState(()=>_isAdding=false);}}@overrideWidgetbuild(BuildContextcontext){returnBadge(label:Text('$_itemCount'),isLabelVisible:_itemCount>0,child:IconButton(icon:_isAdding?constSizedBox(width:20,height:20,child:CircularProgressIndicator(strokeWidth:2),):constIcon(Icons.shopping_cart),onPressed:_isAdding?null:_addToCart,),);}}

1.2 ValueNotifier + ValueListenableBuilder

比 setState 更加精细,避免整个 Widget 重建:

classCounterPageextendsStatelessWidget{final_counter=ValueNotifier<int>(0);CounterPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:Center(// 只有 ValueListenableBuilder 内部重建,不影响整个页面child:ValueListenableBuilder<int>(valueListenable:_counter,builder:(context,value,child){returnText('Count:$value',style:constTextStyle(fontSize:24));},),),floatingActionButton:FloatingActionButton(onPressed:()=>_counter.value++,child:constIcon(Icons.add),),);}}

1.3 setState 的正确姿势

// ✅ 只在 setState 中修改状态setState((){_isLoading=true;_errorMessage=null;});// ❌ 错误:在 setState 外修改,可能导致 UI 不更新_isLoading=true;// 没有通知 Flutter 重建setState((){});// 空 setState(不推荐)// ✅ 避免在 setState 中做耗时操作setState((){// 只做赋值,不做网络请求或复杂计算_data=newData;});

二、InheritedWidget 进阶:跨组件共享数据

InheritedWidget是 Flutter 状态共享的底层机制,Provider 等第三方框架都基于它实现。

2.1 基本实现

// 1. 定义 InheritedWidgetclassThemeInheritedextendsInheritedWidget{finalThemeDatathemeData;finalVoidCallbacktoggleTheme;constThemeInherited({super.key,requiredthis.themeData,requiredthis.toggleTheme,requiredsuper.child,});// 提供 of 方法,方便子 Widget 获取staticThemeInheritedof(BuildContextcontext){finalresult=context.dependOnInheritedWidgetOfExactType<ThemeInherited>();assert(result!=null,'No ThemeInherited found in context');returnresult!;}// 决定何时通知依赖的子 Widget 更新@overrideboolupdateShouldNotify(ThemeInheritedoldWidget){returnthemeData!=oldWidget.themeData;}}// 2. 在祖先 Widget 中提供classAppRootextendsStatefulWidget{@overrideState<AppRoot>createState()=>_AppRootState();}class_AppRootStateextendsState<AppRoot>{ThemeData_theme=ThemeData.light();void_toggleTheme(){setState((){_theme=_theme.brightness==Brightness.light?ThemeData.dark():ThemeData.light();});}@overrideWidgetbuild(BuildContextcontext){returnThemeInherited(themeData:_theme,toggleTheme:_toggleTheme,child:MaterialApp(theme:_theme,home:constHomePage()),);}}// 3. 在任意子 Widget 中消费classThemeToggleButtonextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalinherited=ThemeInherited.of(context);returnSwitch(value:inherited.themeData.brightness==Brightness.dark,onChanged:(_)=>inherited.toggleTheme(),);}}

2.2 maybeOf vs of

// of:找不到时直接 assert 报错(推荐必须依赖时使用)staticMyDataof(BuildContextcontext)=>context.dependOnInheritedWidgetOfExactType<MyData>()!;// maybeOf:找不到时返回 null(可选依赖时使用)staticMyData?maybeOf(BuildContextcontext)=>context.dependOnInheritedWidgetOfExactType<MyData>();

三、Provider 体系

Provider 是 Flutter 官方推荐的状态管理方案,基于 InheritedWidget,提供更简洁的 API。

3.1 安装

dependencies:provider:^6.1.0

3.2 ChangeNotifier + Provider

第一步:定义 ChangeNotifier 模型

classCartModelextendsChangeNotifier{finalList<CartItem>_items=[];List<CartItem>getitems=>List.unmodifiable(_items);// 只读访问intgetitemCount=>_items.length;doublegettotalPrice=>_items.fold(0,(sum,item)=>sum+item.price*item.quantity);voidaddItem(Productproduct){finalindex=_items.indexWhere((item)=>item.productId==product.id);if(index>=0){_items[index]=_items[index].copyWith(quantity:_items[index].quantity+1,);}else{_items.add(CartItem.fromProduct(product));}notifyListeners();// 通知所有监听者重建}voidremoveItem(StringproductId){_items.removeWhere((item)=>item.productId==productId);notifyListeners();}voidclear(){_items.clear();notifyListeners();}}

第二步:在 Widget 树中注入

// 单个 ProviderChangeNotifierProvider<CartModel>(create:(_)=>CartModel(),child:constMyApp(),)// 多个 ProviderMultiProvider(providers:[ChangeNotifierProvider(create:(_)=>CartModel()),ChangeNotifierProvider(create:(_)=>UserModel()),ChangeNotifierProvider(create:(_)=>ThemeModel()),// Provider.value:共享已有实例Provider<ApiService>.value(value:ApiService.instance),],child:constMyApp(),)

第三步:在子 Widget 中消费

// 方式一:Provider.of(会触发整个 Widget 重建)Widgetbuild(BuildContextcontext){finalcart=Provider.of<CartModel>(context);returnText('共${cart.itemCount}件商品');}// 方式二:context.watch(效果同上,语法更简洁)Widgetbuild(BuildContextcontext){finalcart=context.watch<CartModel>();returnText('共${cart.itemCount}件商品');}// 方式三:context.read(仅读取,不监听,不触发重建)ElevatedButton(onPressed:()=>context.read<CartModel>().addItem(product),child:constText('加入购物车'),)// 方式四:context.select(精确监听特定字段)Widgetbuild(BuildContextcontext){// 只有 itemCount 变化才重建,totalPrice 变化不触发finalcount=context.select<CartModel,int>((cart)=>cart.itemCount);returnText('共$count件');}

3.3 Consumer

提供更细粒度的重建控制:

Scaffold(appBar:AppBar(title:constText('购物车'),actions:[// Consumer:只有 CartModel 变化时,这里才重建Consumer<CartModel>(builder:(context,cart,child){returnBadge(label:Text('${cart.itemCount}'),child:child!,);},child:constIcon(Icons.shopping_cart),// 静态子 Widget,不随状态重建),],),body:Consumer<CartModel>(builder:(context,cart,_){if(cart.items.isEmpty){returnconstEmptyCartWidget();}returnCartItemList(items:cart.items);},),)

3.4 Selector

比 Consumer 更精细,只监听状态的部分字段:

// 只有 totalPrice 变化才重建此组件Selector<CartModel,double>(selector:(_,cart)=>cart.totalPrice,builder:(context,totalPrice,_){returnText('总计:¥${totalPrice.toStringAsFixed(2)}',style:Theme.of(context).textTheme.titleLarge,);},)// 监听多个字段Selector<CartModel,(int,double)>(selector:(_,cart)=>(cart.itemCount,cart.totalPrice),builder:(context,(count,price),_){returnText('$count件,¥${price.toStringAsFixed(2)}');},)

3.5 ProxyProvider(派生状态)

MultiProvider(providers:[Provider<ApiService>(create:(_)=>ApiService()),// ProductRepository 依赖 ApiServiceProxyProvider<ApiService,ProductRepository>(update:(_,apiService,__)=>ProductRepository(apiService),),// 监听用户状态变化,派生出相关数据ChangeNotifierProxyProvider<UserModel,CartModel>(create:(_)=>CartModel(),update:(_,user,cart)=>cart!..updateUser(user),),],child:constMyApp(),)

小结

方案适用场景重建粒度复杂度
setState单 Widget 内的局部状态整个 Widget最低
ValueNotifier局部,需要精细控制仅 ValueListenableBuilder
InheritedWidget框架级数据共享依赖的子 Widget
Provider.of全局状态消费整个 Widget
Consumer局部重建Consumer 内部
Selector精确字段监听仅选择字段变化时

👉 下一节:3.3 第三方框架(GetX / Riverpod / Bloc)

http://www.jsqmd.com/news/631996/

相关文章:

  • StructBERT中文相似度模型部署案例:百度千帆大模型平台私有化部署实录
  • 告别命令行恐惧:在恒源云GPU服务器上部署Linux桌面环境全攻略
  • 企业级区块链实战指南:从零构建可信分布式应用
  • Heltec ESP32 OLED显示库深度解析与工程实践
  • 打造个性化设计系统:基于 awesome-design-systems 的定制化指南
  • Malimite插件开发教程:扩展自定义反编译功能的完整指南
  • STM32F042轻量级内建调试工具DEBUG_F042F6P6
  • 那些你不知道自己需要监控的 Linux 暗坑疤
  • 痞子衡嵌入式:turbo-spiboot - 一种基于MCUBoot协议的二级SPI加载APP提速方案犹
  • MOREbot轻量级嵌入式机器人运动控制库
  • Matlab实战:3种雷达成像算法对比(RD/CS/RMA)附完整代码
  • Edge浏览器搞定Kaggle注册验证码报错:Captcha must be filled out的3步终极方案
  • Sixfab NB-IoT Shield 底层驱动与AT指令深度解析
  • 一天一个Python库:oauthlib - 轻松构建OAuth客户端和服务器凉
  • Contribute-To-This-Project项目深度解析:为什么这是最适合新手的开源入门项目
  • 扩散模型对抗样本经典baselines窒
  • 关于CUDA+QtCreator+OpenCV环境配置的一些注意事项
  • 智能楼宇群协同能量管理:主从博弈与需求响应在热电联供中的应用探索
  • Windows本地免服务器,5分钟搞定WeNet语音识别Demo(保姆级教程)
  • 新编大学德语1第三版笔记 第7课Kaufen und Schenken
  • 新手入门编程选C语言!超详细零基础入门指南请查收
  • 避坑指南:ROS仿真中Xacro宏定义常犯的5个错误(以Arbotix控制小车为例)
  • CNCjs高级配置技巧:从端口设置到远程访问
  • 将 fnOS 从 eMMC/TF 卡无损迁移至外部存储(NVMe/USB/SATA/TF)的完整方案 —— 适用于瑞芯微 RK 系列平台(含小容量盘适配)
  • 万象视界灵坛参数详解:ViT-L/14图像编码器与文本编码器协同机制
  • 2026年商业反不正当竞争调查服务标杆名录:知识产权打假人、知识产权维权、知识产权调查、商业不正当竞争调查、商业泄密调查选择指南 - 优质品牌商家
  • 固体废弃物检测数据集6494张VOC+YOLO格式
  • 从零开发 ERP 财务辅助 Agent(Demo:DeepSeek API + 本地模拟)
  • 换季护肤要素
  • Linux网络编程核心API速查手册古