You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中HookWidget搭配Riverpod时StateNotifier更新后页面不重建

问题原因分析
  • 你调用useProvider(orderStateNotifierProvider.notifier)获取的是StateNotifier控制器实例本身,这个实例在Provider生命周期内不会发生变化,所以监听它不会触发任何重建
  • 你的_serviceList是直接从控制器实例的getServices()方法读取的临时值,没有和Provider的状态监听逻辑绑定,状态更新后这个值不会自动同步,也不会触发组件重建
  • 你代码里的Consumer完全没有调用watch方法监听orderStateNotifierProvider的状态,所以即使状态变更,Consumer也不会触发重绘
修复方案
  1. 先确保你的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;
}
  1. 组件中需要监听状态的位置,直接监听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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 18:39:02