如何在Flutter中嵌套StreamBuilders? [英] How can you nest StreamBuilders in Flutter?

查看:146
本文介绍了如何在Flutter中嵌套StreamBuilders?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要结合2个流来构建一个小部件,但是与其他问题不同,我已经看到我需要嵌套流。

I have 2 Streams that I need to combine to build a widget, but unlike other questions I have seen I need to nest my streams.

我有一个流从Firestore获取文档集合,并且有一个流依赖于第一个数据来获取文档的子集合。我想将它们组合成一个流,但是由于每个文档都有自己的文档子集合,因此需要嵌套它们。

I have a stream that gets a collection of documents from Firestore, and a stream that depends on data from the first to get a subcollection of documents. I would like to combine these into one stream, but they need to be nested since each document has its own subcollection of documents.

流1(从中获取习惯的集合) FireStore):

Stream 1 (Gets a collection of habits from FireStore):

Stream<List> getHabits(){
  final Stream<QuerySnapshot> documents = Firestore.instance
    .collection("users")
    .document('VtL1sxOoCOdJaOTT87IbMRwBe282')
    .collection("habits")
    .snapshots();

  Stream<List> data = documents.map((doc) {
    List data;
    final documents = doc.documents;
    ///Maybe this would work to get history of each doc? 
    for(int i = 0; i < documents.length; i++){
      ///not sure what to do
      getHistory(documents[i].documentID, DateTime.utc(2019,7,7), DateTime.now());
    }

    data = documents.map((documentSnapshot) => documentSnapshot).toList();

    return data;
  });

  return data;
}

流2(在流1中调用,采用 DocumentID 作为参数,获取文档的子集合):

Stream 2 (Called in Stream 1, Takes DocumentID as a parameter, gets sub-collection of documents):

Stream<List> getHistory(String id, DateTime start, DateTime end) async* {
  await for (QuerySnapshot querySnapshot in Firestore.instance
    .collection("users")
    .document('VtL1sxOoCOdJaOTT87IbMRwBe282')
    .collection("habits")
    .document(id)
    .collection("history")
    .where('day', isGreaterThanOrEqualTo: start)
    .where('day', isLessThanOrEqualTo: end)
    .snapshots()) {

      List history;
      final documents = querySnapshot.documents;

      history = documents.map((documentSnapshot) => documentSnapshot).toList();

      yield history;
    }
}

有关如何将这些流合并到将嵌套格式集成到一个流中,以便与 StreamBuilder 一起使用时会很感激!'

Any help on how I can combine these streams in a nested format into one stream to be used with StreamBuilder in flutter would be appreciated!'

EDIT
我不确定我是否在朝着正确的方向工作,但我尝试通过spenster实现解决方案,这是我目前除了上述功能之外的功能。

EDIT I am not sure if I am working in the right direction or not but I have tried to implement the solution from spenster and this is what I have at the moment in addition to the functions above.

StreamBuilder<List>(
  stream: getHabits(),
  initialData: [],
  builder: (context, snapshot) {
    List<UserHabit> habits = [];
    List<Widget> test = List.generate(snapshot.data.length, (index){
      List<History> history = [];
      DocumentSnapshot doc = snapshot.data[index];
      return StreamBuilder(
        stream: getHistory(doc.documentID, DateTime.utc(2019,7,7), DateTime.now()),
        builder: (context, snapshot) {
          if (snapshot.hasError)
            return new Text('Error: ${snapshot.error}');
          switch (snapshot.connectionState) {
            case ConnectionState.waiting: return new Text('Loading...');
            default:
              if(!snapshot.data.isEmpty){ //history collection exists
                for(int i = 0; i < snapshot.data.length; i++){
                  //add to history
                  history.add(History(
                    day: snapshot.data[i]['day'].toDate(), 
                    dateCompleted: snapshot.data[i]['dateCompleted'].toDate(), 
                    morning: snapshot.data[i]['morning'],
                    afternoon: snapshot.data[i]['afternoon'],
                    evening: snapshot.data[i]['evening'],
                    anytime: snapshot.data[i]['anytime'],
                  ));
                }
              }
              habits.add(UserHabit(
                name: doc['habit'],
                color: doc['color'],
                icon: doc['icon'],
                repeat: doc['repeat'],
                daily: doc['daily'],
                weekly: doc['weekly'],
                monthly: doc['monthly'],
                time: doc['time'],
                history: history,
              ));
              print(habits); //returns each iteration of assembling the list
              return Text("i dont want to return anything");
          }
        },
      );
      }
    );
    print(habits); //returns empty list before anything is added
    return Column(
      children: test,
    );

  },
),

用户习惯和历史可以共享,但是它们只是分配类型并允许轻松访问的基本类。

The Class for UserHabits and History can be shared, but they are just basic classes that assign types and allow easy access.

推荐答案

我只是使用嵌套的 StreamBuilders 做过类似的事情。根据您希望 Widget 的组织方式,可以在外部 StreamBuilder 中创建流。根据您的澄清意见,这是一种可能性:

I have done something similar simply using nested StreamBuilders. Depending on how you want your Widgets organized, you can create streams within the outer StreamBuilder. Based on your clarifying comments, this is one possibility:

@override
Widget build(BuildContext context) {

  var habits = Firestore.instance
    .collection("users")
    .document('VtL1sxOoCOdJaOTT87IbMRwBe282')
    .collection("habits")
    .snapshots();

  return StreamBuilder<QuerySnapshot>(
    stream: habits,
    builder: (context, snapshot) {

      if (!snapshot.hasData)
        return Text("Loading habits...");

      return ListView(children: snapshot.data.documents.map((document) {

        var query = Firestore.instance
          .collection("users")
          .document('VtL1sxOoCOdJaOTT87IbMRwBe282')
          .collection("habits")
          .document(document.documentID)
          .collection("history")
          .where('day', isGreaterThanOrEqualTo: start)
          .where('day', isLessThanOrEqualTo: end)
          .snapshots();

        return StreamBuilder<QuerySnapshot>(
          stream: query,
          builder: (context, snapshot) {

            if (!snapshot.hasData) return Text("Loading...");

            // right here is where you need to put the widget that you
            // want to create for the history entries in snapshot.data...
            return Container();
          },
        );
      }).toList());
    },
  );
}

这篇关于如何在Flutter中嵌套StreamBuilders?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆