I am creating like system and i want to get likeCount from firebase which i created.
It's collecting it but returns null, here is my code:
String? getLikecount(tresc) {
String? likeCount;
FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get()
.then((value) => value.docs.forEach((element) async {
var id = element.id;
final value = await FirebaseFirestore.instance.collection('Posty').doc(id).get();
likeCount = value.data()!['likeCount'].toString();
print(likeCount);
}));
print(likeCount);
return likeCount;
}
and here is console output:
CodePudding user response:
Data is loaded from Firestore (and most modern cloud APIs) asynchronously, because it may needs to come from the network and we can't block your code (and your users) while waiting for it.
If we change the print statements a bit, and format the code, it'll be much easier to see what's going on:
String? getLikecount(tresc) {
String? likeCount;
FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get()
.then((value) => value.docs.forEach((element) async {
var id = element.id;
final value = await FirebaseFirestore.instance
.collection('Posty')
.doc(id)
.get();
likeCount = value.data()!['likeCount'].toString();
print('In then: $likeCount');
}));
print('After then: $likeCount');
return likeCount;
}
If you run this, you'll see it outputs:
After then: null
In then: 0
This is probably not what you expected, but it explains perfectly why you don't get a result. By the time your return likeCount
runs, the likeCount = value.data()!['likeCount'].toString()
hasn't executed yet.
The solution is always the same: any code that needs the data from the database has to be inside the then
handler, be called from there, or be otherwise synchronized.
In Flutter it is most common to use async
and await
for this. The key thing to realize is that you can't return something now that hasn't been loaded yet. With async
/await
you function becomes:
Future<String?> getLikecount(tresc) {
String? likeCount;
var value = await FirebaseFirestore.instance
.collection('Posty')
.where('Tresc', isEqualTo: tresc)
.get();
for (var doc in value.docs) {
var id = element.id;
final value = await FirebaseFirestore.instance
.collection('Posty')
.doc(id)
.get();
likeCount = value.data()!['likeCount'].toString();
print('In then: $likeCount');
}));
print('After then: $likeCount');
return likeCount;
}
Now your code returns a Future<String?>
so a value that at some point will hold the string. When calling getLikecount
you will now need to use then
or await
to handle the Future
, and if you want to show the count in the UI you will have to store it in the State
of a StatefulWidget
.