Flutter中在where方法使用类构造参数时出现widget未定义错误
问题:State类中初始化Stream时无法访问widget参数
问题重现
尝试在StatefulWidget构造函数传入字符串参数campoPesquisaNome,并在对应的State类中使用widget.campoPesquisaNome作为Firestore查询的条件,但编译报错。
示例代码
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; class listFireBase extends StatefulWidget { final String campoPesquisaNome; listFireBase(this.campoPesquisaNome, {Key? key}) : super(key: key); @override State<listFireBase> createState() => _listFireBaseState(); } class _listFireBaseState extends State<listFireBase> { final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance .collection('MeusContatos') .where('Nome', isEqualTo: widget.campoPesquisaNome) // 报错位置 .snapshots(); // 其余代码... }
错误信息
lib/list-firebase.dart:15:33: Error: Undefined name 'widget'. .where('Nome', isEqualTo: widget.campoPesquisaNome) ^^^^^^
问题原因
在State类中,成员变量的初始化时机早于widget属性的绑定。当你直接在成员变量定义处使用widget时,widget还未被Flutter框架初始化,因此会提示未定义。
解决方案
提供两种可行的解决办法:
方法1:使用late延迟初始化
将_usersStream声明为late,延迟到initState中初始化,此时widget已经可用:
class _listFireBaseState extends State<listFireBase> { late final Stream<QuerySnapshot> _usersStream; @override void initState() { super.initState(); _usersStream = FirebaseFirestore.instance .collection('MeusContatos') .where('Nome', isEqualTo: widget.campoPesquisaNome) .snapshots(); } // 其余代码... }
方法2:在StreamBuilder中动态构建Stream
如果需要在widget.campoPesquisaNome变化时自动更新查询,可以直接在StreamBuilder的stream参数中构建查询,这样每次widget参数变化时都会重新生成Stream:
class _listFireBaseState extends State<listFireBase> { @override Widget build(BuildContext context) { return StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection('MeusContatos') .where('Nome', isEqualTo: widget.campoPesquisaNome) .snapshots(), builder: (context, snapshot) { // 处理快照并构建UI if (snapshot.hasError) { return const Text('加载出错'); } if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } return ListView( children: snapshot.data!.docs.map((DocumentSnapshot document) { Map<String, dynamic> data = document.data()! as Map<String, dynamic>; return ListTile( title: Text(data['Nome']), ); }).toList(), ); }, ); } }
注意:如果使用方法1,当widget.campoPesquisaNome发生变化时,_usersStream不会自动更新,需要额外监听didUpdateWidget方法来重新初始化Stream;而方法2会自动响应widget参数的变化,更适合参数可能动态改变的场景。
内容的提问来源于stack exchange,提问作者Ramon Basilio
相关产品推荐
相关产品推荐

