如何在Flutter中嵌套StreamBuilders? [英] How can you nest StreamBuilders in Flutter?
问题描述
我需要结合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 Widget
s 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屋!