flutter - 需要访问 2 个集合的 Flutter、Firestore 和 FutureBuilder
问题描述
我正在尝试使用 Flutter 中的 FutureBuilder 从 Firestore 中的数据创建一个列表视图,但从文档和其他类似问题来看,我似乎无法使我正在尝试做的工作。
我在 Firestore 上有两个集合,一个是 for users
,一个是 items items
。
该users
集合包含一个 id 数组items
。
我想访问user
'sitem
列表,获取所有item
id,然后使用它们来获取每个单独的item's
数据。
目前我有一些工作,但不完全按照我想要的方式,因为我无法在创建之前对列表进行排序ListView
,而且我知道它到目前为止还没有优化。
这是我用来实现此目的的代码的简化版本。
以下代码用于从 Firestore 访问文档快照。
Future getUserInfo(User user) async{
// Gets Current user's collection
DocumentReference userIdRef = usersCollection.document(user.getUid());
DocumentSnapshot userIdSnapshot = await userIdRef.get();
return userIdSnapshot.data;
}
Future getItemInfo(String itemId) async{
DocumentReference itemIdRef = itemCollection.document(itemId);
DocumentSnapshot itemIdSnapshot = await itemIdRef.get();
return itemIdSnapshot.data;
}
在 Widget 树中,我有两个 FutureBuilder,一个嵌套在另一个内部以创建一个列表。(我已经删除了这个问题的细节
class _TestState extends State<Test> {
FirestoreDatabase firestoreDatabase = new FirestoreDatabase();
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
body: getUserItemsFromFirestore(user),
);
}
Widget getUserItemsFromFirestore(User user) {
FirestoreDatabase firestore = new FirestoreDatabase(uid: user.getUid());
return FutureBuilder(
future: firestore.getUserInfo(user),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingSpinner();
} else if (snapshot.connectionState == ConnectionState.done ||
snapshot.connectionState == ConnectionState.active) {
//List<MedicationRegime> medicationList = snapshot.data ?? [];
return ListView.builder(
itemCount: snapshot.data['item'].length,
itemBuilder: (context, index) {
return getItemList(
snapshot.data['item'][index], user, index);
},
);
} else {
return null;
}
});
}
Widget getItemList(String itemID, User user, int index) {
FirestoreDatabase firestore = new FirestoreDatabase(uid: user.getUid());
return FutureBuilder(
future: firestore.getItemInfo(itemID),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingSpinner();
} else if (snapshot.connectionState == ConnectionState.done ||
snapshot.connectionState == ConnectionState.active) {
List itemList = [];
Item item = new Item(
itemID: itemID,
name: snapshot.data['name'],
type: snapshot.data['type']
);
itemList.add(item);
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: itemList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(itemList[index]
.getitemIcon()),
title: Text(
itemList[index].getName(),
),
subtitle: Text(itemList[index].getType()),
],
),
);
);
});
} else {
return null;
}
});
}
}
有没有办法将这两者合并到一个 FutureBuilder 中,因为我需要getUserInfo()
在调用之前运行,getItemInfo
所以我不能使用Future.wait([getUserInfo, getItemInfo])
. 谢谢
解决方案
return FutureBuilder(
future: firestore.getUserInfo(user)
.then((userInfo)=>firestore.getItemInfo(userInfo.data['itemID'])]),
builder: (context, itemInfoSnapshot) {
}
您可以链接期货,您返回的最后一个期货将是未来建造者使用的期货。
如果您在未来构建器中需要这两个数据,您可以创建自己的未来。
class CustomResponse {
String userName;
String itemName;
CustomResponse(this.userName,this.itemName);
}
Future<CustomResponse> customFuture() async {
var userInfo = await firestore.getUserInfo();
var itemInfo = await firestore.getItemInfo();
return CustomResponse(userInfo['name'],itemInfo['name']);
}
FutureBuilder(
future: customFuture(),
builder: (context, customResponse) {
}
推荐阅读
- java - 安卓; 执行方法时如何显示按钮
- xcode - xcode 8 无法在 macOS 10.14 上打开
- android - 如何在android的编辑文本中显示错误消息?
- sql - Oracle SQL:向日期添加小时数
- perl - 如何在bash中分隔一列的字段?
- neo4j - Neo4J 桌面版:数据库无法重新启动:数据库 [database-f6b0d9de-9954-4197-955c-ceb200b57d92] 'v3.4.7' 退出,状态为 'KILLED'
- c++ - 带有函数指针的 C++ 运算符优先级
- php - 如何传递资源查看?
- javascript - 如何理解这个 Node.js 代码片段?
- python - 使用 Python 在不同模块中导入函数的返回值时出错