首页 > 解决方案 > 需要访问 2 个集合的 Flutter、Firestore 和 FutureBuilder

问题描述

我正在尝试使用 Flutter 中的 FutureBuilder 从 Firestore 中的数据创建一个列表视图,但从文档和其他类似问题来看,我似乎无法使我正在尝试做的工作。

我在 Firestore 上有两个集合,一个是 for users,一个是 items items

users集合包含一个 id 数组items

我想访问user'sitem列表,获取所有itemid,然后使用它们来获取每个单独的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]). 谢谢

标签: flutterdart

解决方案


  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) {

      }


推荐阅读