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

Flutter Riverpod疑问:为何两种写法下状态表现不一致?

Riverpod两种watch场景状态差异的原因

两种场景的行为差异,核心是对randomNumberProvider的订阅生命周期不同,再结合Riverpod的Provider缓存机制导致的。

第一种场景:在Widget build顶部订阅Provider

保留以下代码时:

final num = ref.watch(randomNumberProvider); // comment this
// ...
children: [Text(num), Text(num)], // comment this
  • MyApp的build方法执行时,第一行就通过ref.watch订阅了randomNumberProvider,只要MyApp这个Widget存在,它就会一直是该Provider的活跃订阅者。
  • Riverpod的Provider会在有活跃订阅者时,永久缓存其状态值。所以每次giveBoolProvider变化触发MyApp重新build时,ref.watch直接返回缓存的旧值,不会重新执行RandomNumber的build方法。
  • 这就是为什么多次点击按钮,显示的随机数始终不变。

第二种场景:在条件分支内订阅Provider

切换为以下代码时:

// final num = ref.watch(randomNumberProvider); // comment this
// ...
children: [Text(ref.watch(randomNumberProvider)), Text(ref.watch(randomNumberProvider))], // uncomment this
  • 初始状态下,giveBoolProvider为false,条件分支不执行,此时没有任何代码订阅randomNumberProvider,Riverpod会自动清理它的缓存。
  • 第一次点击按钮,giveBoolProvider变为true,条件分支执行,ref.watch触发订阅。因为缓存已被清理,Provider会执行build方法生成新随机数并缓存。
  • 第二次点击按钮,giveBoolProvider变回false,条件分支被移除,randomNumberProvider的订阅者数量降为0,Riverpod销毁它的缓存。
  • 第三次点击按钮,giveBoolProvider再次变为true,条件分支执行,ref.watch再次触发订阅,但缓存已不存在,Provider只能重新执行build生成新随机数。
  • 每次切换giveBool状态,都会重复“订阅-取消订阅-缓存销毁-重新订阅-重新生成值”的流程,所以每次点击都会看到新的随机数。

额外说明

虽然你在children里写了两次ref.watch(randomNumberProvider),但在同一个build周期内,多次watch同一个Provider会返回同一个缓存值,所以两个Text显示的是同一个随机数,不会出现差异。

内容的提问来源于stack exchange,提问作者wafaa sisalem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:08:10