为何未设置listen: false时Provider.of<>无法正常工作?
问题:为何Provider.of<>()在GestureDetector的onTap()回调中无法工作?
我有一个简单的组件树,尝试调用模型方法时发现Provider.of<>()在GestureDetector的onTap()回调中无法工作,但改为Provider.of<ShareObjectProvider>(context, listen: false).increment()后就能正常运行,想知道原因。
模型代码
class ShareObject { int intField; ShareObject(this.intField); } class ShareObjectProvider extends ShareObject with ChangeNotifier { ShareObjectProvider(super.intField); void increment() { intField++; notifyListeners(); } }
组件树代码
class ParentWidgetState extends State<ParentWidget> { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ShareObjectProvider(0), child: Scaffold( body: const WidgetThree(), ), ); } } class WidgetThree extends StatelessWidget { const WidgetThree({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: SizedBox( width: 200, height: 200, child: Container( color: Colors.deepOrange, child: Center( child: GestureDetector( onTap: () => {Provider.of<ShareObjectProvider>(context).increment()}, child: Text( "Test ${Provider.of<ShareObjectProvider>(context).intField}", style: const TextStyle(color: Colors.blueAccent), ), ) ), ), ), ); } }
原因解析
Provider.of<T>(context)的默认参数是listen: true,这会让当前Widget订阅ChangeNotifier的状态变化,一旦状态更新就会触发Widget重建。- 在
onTap回调中调用带默认listen: true的Provider.of时,相当于在Widget构建完成后尝试订阅状态变化,这违反了Flutter的Widget生命周期规则——订阅操作只能在build方法内执行,否则会触发框架报错。 - 当设置
listen: false时,Provider.of只会获取当前的ChangeNotifier实例,不会订阅状态变化,这符合回调函数的使用场景:我们只需要调用模型的方法,不需要在这个回调里监听状态更新(状态更新后的UI重建已经由build方法中那个listen: true的Provider.of负责了)。
简单来说,回调里不需要监听状态变化,只需要拿实例调用方法,所以必须加listen: false;而build方法里的Provider.of需要监听变化来更新UI,所以用默认的listen: true就没问题。
内容的提问来源于stack exchange,提问作者Kamil Komnacki
相关产品推荐
相关产品推荐

