I've looked at a number (~30) stackoverflow posts that are all similar, and yet none seem to be able to make me understand what I'm doing wrong. Some examples:
setState in futureBuilder Flutter - Wait setState in FutureBuilder then load component
Some answers, like the one immediately above, say that setState should never be used with FutureBuilder, Aand yet other upvoted and accepted answers say that doing so is the solution to my problem. Example:
Reload data when using FutureBuilder
So what I am actually doing is I want to implement pagination for some product documents. So I pull data with this method:
static Future<List<String>> limitNumberByField(String collection, String field,
String desiredValue, int limit, String? startAfterDocId) async {
List<String> docs = [];
FirebaseFirestore db = FirebaseFirestore.instance;
CollectionReference collectionRef = db.collection(collection);
Query filteredQuery = collectionRef
.where(field, isEqualTo: desiredValue)
.limit(limit);
if (startAfterDocId != null) {
DocumentSnapshot startAfterDoc = await collectionRef.doc(startAfterDocId).get();
filteredQuery = filteredQuery.startAfterDocument(startAfterDoc);
}
await filteredQuery.get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) => {
docs.add(doc.id)
})
});
return docs;
}
This works as expected. The first page also displays exactly as I want. But when I press a button to load the next page, in which I call setState(), it just breaks. The FutureBuilder's future calls a function that calls the above function to get a list of DocumentID's and then builds buttons according to each. But instead of creating a new list on button press, it displays my custom message that displays only when there is no data in snapshot and when the connectionState is done.
The code:
The build method in the above link:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getProducts(context),
builder: (context, snapshot) {
if (!snapshot.hasData && snapshot.connectionState == ConnectionState.done) {
return const Text(
'ERROR: Could not load data',
);
} else if (snapshot.hasData) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_curPage > 1 ? LeftArrow(callback: () => setState(() {
_curPage--;
})) : Container(),
_nextPageAvailable ? RightArrow(callback: () => setState(() {
_curPage++;
})) : Container(),
],
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
padding: const EdgeInsets.all(8.0),
width: double.infinity,
height: 400,
decoration: _boxDecoration(),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
SectionLabel(AppLocalizations.of(context)!.availableProducts),
Column(
children: snapshot.data!,
),
],
),
),
),
),
],
);
} else {
return const CircularProgressIndicator();
}
}
);
}
>(ConnectionState.active, [CategorySelectionButton, CategorySelectionButton, CategorySelectionButton, CategorySelectionButton, CategorySelectionButton, CategorySelectionButton, CategorySelectionButton], null, null)
– Riverreed Ward Apr 17 '23 at 12:12>(ConnectionState.active, [CategorySelectionButton, CategorySelectionButton, CategorySelectionButton], null, null) They looked identical, so I didn't bother post both. Should have specified
– Riverreed Ward Apr 17 '23 at 13:36