【问题标题】:How can you nest StreamBuilders in Flutter?如何在 Flutter 中嵌套 StreamBuilder?
【发布时间】:2019-12-10 04:42:31
【问题描述】:

我需要将 2 个 Streams 组合起来以构建一个小部件,但与我见过的其他问题不同,我需要嵌套我的流。

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

Stream 1(从 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;
}

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

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 一起使用的任何帮助将不胜感激!'

编辑 我不确定我的工作方向是否正确,但我已尝试从 spenster 实施解决方案,这是我目前除了上述功能之外的功能。

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,
    );

  },
),

UserHabits 和 History 的类可以共享,但它们只是分配类型并允许轻松访问的基本类。

【问题讨论】:

    标签: flutter dart stream google-cloud-firestore


    【解决方案1】:

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

    @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());
        },
      );
    }
    

    【讨论】:

    • 谢谢!我会试一试,如果可行,我会将您的答案标记为正确!感谢您花时间回答问题!
    • 只是出于好奇,有什么办法我不能在getHistoryStreamBuilder 中不返回任何内容吗?我需要使用history 数据列表来查看事情是否已完成,但我只在getHabits() 中为每个项目构建一个小部件
    • 我也收到以下错误The element type 'Set&lt;StreamBuilder&lt;List&gt;&gt;' can't be assigned to the list type 'Widget'.
    • 如果您只想要历史收藏中的一个文档,那么您可以使用 Firestore 来选择它(比如在查询中使用 .limit(1)),然后只构建一个小部件。这也应该顺便消除您也看到的其他错误。我会看看我是否可以更新答案...
    • 我想我设法让这种方法起作用,但我觉得应该有一种方法可以嵌套流而不需要嵌套流构建器。或者firebase应该更容易访问子文档哈哈。非常感谢您抽出宝贵的时间,我会将其标记为正确的!大约一周以来一直在解决这个难题。
    【解决方案2】:

    尝试将您的流与Observable.zip2(stream1,stream2,zipper)Observable.combineLatest2(streamA, streamB, combiner) 之类的内容合并。

    欲了解更多信息,请查看post

    【讨论】:

    • 我喜欢这个方向,但第二个流取决于第一个流中项目的documentID。第二个流对于每个项目都与第一个不同。我需要它们以某种方式嵌套而不是压缩
    猜你喜欢
    • 2020-12-19
    • 2021-02-28
    • 2022-12-25
    • 2020-10-02
    • 2019-11-29
    • 2020-06-25
    • 1970-01-01
    • 2017-12-29
    • 2021-05-17
    相关资源
    最近更新 更多