For some reason, Future.wait()
is constantly returning null
. I'm not completely certain I am using it correctly.
For context, I have a collection of posts
in Firebase. For each post, I can extract the userID
assigned to it, then for each post individually I use the userID
of the poster to grab the username
for display purposes. I grab the Post
from a snapshot:
static Future<Post> fromSnapshot(QueryDocumentSnapshot<Object?> doc) async {
final _documentId = doc.id;
final _title = doc.get('title');
final _text = doc.get('text');
final _createdOn = doc.get('createdOn');
final _userID = doc.get('userID');
final userDoc = await FirebaseFirestore.instance.collection('users').doc(_userID).get();
final username = userDoc.get("username");
return Post(documentId: _documentId, title: _title, text: _text, createdOn: _createdOn, username: username);
}
and the extraction of posts
occurs in a getPosts()
function elsewhere:
Future<List<Post>> getPosts() async {
QuerySnapshot posts = await FirebaseFirestore.instance.collection('posts').get();
final allData = posts.docs.map(
(doc) async => await Post.fromSnapshot(doc)
).toList();
print(allData); // [Instance of 'Future<Post>', Instance of 'Future<Post>', Instance of 'Future<Post>']
final futurePosts = Future.wait(allData);
print(futurePosts); // Instance of 'Future<List<Post>>'
// why does this always return null?
return futurePosts;
}
the problem is it has to be async to extract the posts but also to get the username, meaning it returns a future list of future posts. I want to pass the result of getPosts()
to a FutureBuilder
, so I need a Future List
of posts, and to not make all the posts Future
I use Future.wait
- but that always seems to return null. Essentially, I am mapping each post in the snapshot to its own Post
item, where in the constructor it needs to run a further async
call to extract the username
. Am I missing something?
Note: even making the Future.wait()
await
returns null
, it just also doesn't return a List
of type Future
so I can't use it in the FutureBuilder
either.
Edit 1:
It turns out that futurePosts
is actually an Instance of 'Future<List<Post>>'
, but when accessing the data within the FutureBuilder, snapshot.data
is null
:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Feed'),
),
body: FutureBuilder(
future: getPosts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print(snapshot.data);
return postsToColumn(context, snapshot.data as List<Post>);
}
return const Center(
child: CircularProgressIndicator(),
);
}
),
);
}
CodePudding user response:
Ok, lots of thanks to @IvoBeckers for helping me pin this down. It turns out, the snapshot
actually did have an error, as they said, but this doesn't get printed unless you print it explicitly:
if (snapshot.hasError) {
print(snapshot.error.toString());
}
And the error is
Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist
So it turns out that not every User
has a corresponding entry in the users
collection with its username
, which sounds like something I should have checked before, but I thought such an error would be printed out in the console. Once I updated the users
collection, it worked perfectly.