Flutter中HookWidget搭配Riverpod时StateNotifier更新后页面不重建
问题原因分析
- 你调用
useProvider(orderStateNotifierProvider.notifier)获取的是StateNotifier控制器实例本身,这个实例在Provider生命周期内不会发生变化,所以监听它不会触发任何重建 - 你的
_serviceList是直接从控制器实例的getServices()方法读取的临时值,没有和Provider的状态监听逻辑绑定,状态更新后这个值不会自动同步,也不会触发组件重建 - 你代码里的
Consumer完全没有调用watch方法监听orderStateNotifierProvider的状态,所以即使状态变更,Consumer也不会触发重绘
修复方案
- 先确保你的
StateNotifierProvider定义符合规范,状态变更时会正确返回新的状态值(注意StateNotifier的状态是immutable的,修改时必须赋值新的state对象,不能直接修改原状态的属性)
示例定义参考:
// 示例Provider定义,假设你的状态是选中的服务列表 final orderStateNotifierProvider = StateNotifierProvider<OrderStateNotifier, List<SelectedProductServices>>((ref) { return OrderStateNotifier(); }); class OrderStateNotifier extends StateNotifier<List<SelectedProductServices>> { OrderStateNotifier() : super([]); // 初始状态为空列表 void increment({required int productId, required int serviceId}) { // 必须生成新的状态对象赋值给state,不能直接修改原state的元素 state = [ ...state, SelectedProductServices(productId: productId, serviceId: serviceId) ]; } List<SelectedProductServices> getServices() => state; }
- 组件中需要监听状态的位置,直接监听
orderStateNotifierProvider本身,而非它的notifier:
全页面刷新的修复代码:
class MyHomePage extends HookWidget { @override Widget build(BuildContext context) { // 拿控制器实例,仅用于调用方法,不会触发重建 final _orderNotifier = useProvider(orderStateNotifierProvider.notifier); // 监听状态,状态变更时会自动更新并触发重建 final _serviceList = useProvider(orderStateNotifierProvider); return Scaffold( appBar: AppBar( title: Text('test'), ), body: Center( child: Column( children: <Widget>[ // ... 展示_serviceList的相关组件 GestureDetector( onTap: () => _orderNotifier.increment(productId: 1, serviceId: 1), child: Container( width: 200.0, height: 50.0, child: Text('ADD') ), ) // ... ], ), ) ); } }
如果需要局部刷新避免整个页面重建,可以保留Consumer,在Consumer内部监听状态:
class MyHomePage extends HookWidget { @override Widget build(BuildContext context) { final _orderNotifier = useProvider(orderStateNotifierProvider.notifier); return Scaffold( appBar: AppBar( title: Text('test'), ), body: Center( child: Consumer( builder: (_, watch, __) { // 仅在Consumer内部监听状态,只有Consumer部分会重建 final _serviceList = watch(orderStateNotifierProvider); return Column( children: <Widget>[ // ... 展示_serviceList的相关组件 GestureDetector( onTap: () => _orderNotifier.increment(productId: 1, serviceId: 1), child: Container( width: 200.0, height: 50.0, child: Text('ADD') ), ) // ... ], ); }, ), ) ); } }
核心注意点
- 只有监听Provider的状态值才会触发重建,监听.notifier获取的控制器实例不会触发重建
- StateNotifier的state必须是immutable的,修改状态时必须给state赋值新的对象,直接修改原state的内部属性不会触发状态更新
- Consumer的builder中必须调用watch方法监听对应的Provider,才会在状态变更时重绘
内容的提问来源于stack exchange,提问作者DolDurma
相关产品推荐
相关产品推荐

