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

Flutter中Selector组件调用notifyListeners()时未变更值仍执行builder

问题原因

你代码里的核心问题出在ListenableBuilder的listenable参数使用了context.watch<SomeDataProvider>()。watch方法会让当前的MyHomePage组件订阅SomeDataProvider的变化,一旦调用notifyListeners(),整个MyHomePage的build方法就会被重新执行——这意味着里面所有的Selector、TextButton等子组件都会被重新创建,所以负责展示列表长度的Selector的builder也会被调用,哪怕它监听的beakers根本没变化。

解决方案

把ListenableBuilder里的context.watch改成context.read,因为read只是获取Provider实例,不会让当前组件订阅变化:

ListenableBuilder(
  listenable: context.read<SomeDataProvider>(), // 替换为read
  builder: (context, child) {
    de.log('ListenableBuilder: builder called');
    return Text('${context.read<SomeDataProvider>().beakers.length}');
  },
),
额外说明

Selector本身的逻辑是正常的:它会在notifyListeners()触发时,重新执行selector函数获取新值,然后和旧值用==比较,只有值不同时才会调用builder。但如果父组件因为其他原因(比如误用watch)重建,Selector会被重新初始化,这时候builder也会被调用一次——这是组件重建的正常现象,和Selector的监听逻辑无关。

如果需要更精细的重建控制(比如只关心列表长度变化而非List引用),可以给Selector添加shouldRebuild参数自定义判断条件:

Selector<SomeDataProvider, List<Beaker>>(
  selector: (_,sd)=> sd.beakers,
  shouldRebuild: (previous, next) => previous.length != next.length,
  builder: (context, data, child)  {
    de.log('Selector<Listprovider, List<Beaker>>: builder called for change in list');
    return Text('${data.length}');
  },
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:00:04