如何使用Provider仅更新指定Widget 附实际业务场景实现示例
Provider局部刷新实现方案
问题原因
你当前将Consumer<PositionProvider>包裹在整个Column外层,只要PositionProvider的状态发生变化,Column下所有子组件都会被重绘,包括不需要更新的按钮组,无法实现局部刷新的需求。
实现方案
核心思路是仅在依赖状态变化的组件外层包裹状态监听组件,无关组件完全不放入监听范围内,可选两种实现方式:
方式1:拆分Consumer包裹目标组件
将不依赖状态的按钮组移出Consumer范围,仅给需要更新的两个组件单独套Consumer:
@override Widget build(BuildContext context) { PositionProvider positionProvider = Provider.of(context, listen: false); return Scaffold( appBar: AppBar( title: Text("Test Provider"), ), body: Column( children: [ // 按钮组不依赖Provider状态,无需放入Consumer范围,不会被重绘 Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( onPressed: () => positionProvider.setSelectedPosition("Start"), child: Text("Start")), TextButton( onPressed: () => positionProvider.setSelectedPosition("Center"), child: Text("Center")), TextButton( onPressed: () => positionProvider.setSelectedPosition("End"), child: Text("End")) ], ), // 仅对齐控制的Row依赖选中位置属性,单独套Consumer Consumer<PositionProvider>( builder: (context, value, child) => Row( mainAxisAlignment: value.getSelectedPosition == "Start" ? MainAxisAlignment.start : value.getSelectedPosition == "Center" ? MainAxisAlignment.center : MainAxisAlignment.end, children: [Text("Message")], ), ), // 仅Html组件依赖富文本内容属性,单独套Consumer Consumer<PositionProvider>( builder: (context, value, child) => Html(data: value.getHtmlContents), ) ], ), ); }
方式2:使用Selector实现更细粒度控制
如果你需要更精准的监听(比如某组件只依赖Provider中的单个属性,其他属性变化不需要重绘),可以使用Provider提供的Selector组件,只有监听的属性变化时才会触发重绘,性能更优:
// 仅监听选中位置属性,只有该属性变化时才会重绘对应Row Selector<PositionProvider, String>( selector: (context, provider) => provider.getSelectedPosition, builder: (context, selectedPosition, child) => Row( mainAxisAlignment: selectedPosition == "Start" ? MainAxisAlignment.start : selectedPosition == "Center" ? MainAxisAlignment.center : MainAxisAlignment.end, children: [Text("Message")], ), ), // 仅监听富文本内容属性,只有该属性变化时才会重绘Html组件 Selector<PositionProvider, String>( selector: (context, provider) => provider.getHtmlContents, builder: (context, htmlContents, child) => Html(data: htmlContents), )
注意事项
- 点击事件使用
listen: false获取Provider实例的写法是正确的,不会触发当前组件重绘 - 不要把无状态依赖的组件放入Consumer/Selector的builder回调中,避免不必要的重绘
内容的提问来源于stack exchange,提问作者Aniket Songara
相关产品推荐
相关产品推荐

