如何协调用于授权的StreamBuilder和用于api + listview过滤数据的FutureBuilder.&l



首先,我是新手,我可能会犯一些基本的错误。

初始假设:

  • 使用flutter与firebase认证
  • 使用自己的api获取额外数据
  • api端点返回更多的数据当应用程序发送用户令牌从firebase认证在报头

我的主类:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => GoogleSignInProvider(),
child: MaterialApp(
home: child: MyList()
);
}

和MyList类(我在这个例子中简化了这个类):

class MyList extends StatefulWidget {
MyList();
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
TextEditingController controller = new TextEditingController();
late Future<List<Details>> _detailsList;
Future<List<Details>> getDetailsList() async {
Map<String, String> headers = {};
if (FirebaseAuth.instance.currentUser != null){
headers["tokenID"] = FirebaseAuth.instance.currentUser?.uid;
}
final response = await http
.get(Uri.parse('http://hostname/api/v1/details/list'), headers: headers);
final responseJson = json.decode(response.body);
List<Details> details = [];
for (Map details in responseJson["details"]) {
details.add(Details.fromJson(details));
}
return details;
}
@override
void initState() {
super.initState();
_details = getDetailsList();
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
return FutureBuilder(
future: _details,
builder: (context, AsyncSnapshot<List<Details>> snapshot) {
return new Scaffold(
body: new Column(
children: <Widget>[
new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
new Expanded(
child: _searchResult.length != 0 ||
controller.text.isNotEmpty
? new ListView.builder(
padding: const EdgeInsets.only(top: 10, bottom: 50),
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new ListItem(_searchResult[i]);
},
)
: new ListView.builder(
padding: const EdgeInsets.only(bottom: 40),
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return new ListItem(snapshot.data![index]);
},
),
),
],
),
);
}
);
}
);
}
List<Details> _searchResult = [];
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_details.forEach((userDetail) {
if (userDetail.name.toLowerCase().contains(text.toLowerCase()))
_searchResult.add(userDetail);
});
setState(() {});
}

在这种情况下,过滤/搜索工作良好。但是每个类型的字符执行setState和reinitiationwidget,这导致为每个类型发送API请求-我不希望这样的行为。

另一方面,我想在用户登录或注销时获得一个新的API请求。

我怎样才能做到这一点?

问题第一部分的答案:为了防止setState针对每个类型字符,您需要为TextField实现debounce和throttling。有很多教程都是这样的。

第二部分答案:以firebase验证流为例,在每次需要时基于验证对象执行请求的流上执行asyncMap。asyncMap之后的流将返回List,并在每次验证流更新时更新。

最新更新