0

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(),
          );
        }
    ),
  );
}
10
  • You can use Future.value(allData) Commented Apr 12, 2022 at 9:28
  • 1
    What's the output of this: print(allData);? Commented Apr 12, 2022 at 9:29
  • 1
    To me it seems impossible that it returns null. Future.wait never returns null. At the very least it returns a future that returns an empty list. If getPosts would be able to return null the compiler would already complain also and you couldn't even run your app. What do you exactly mean with "it returns null"? because that simply is impossible Commented Apr 12, 2022 at 9:46
  • @krumpli it prints [Instance of 'Future<Post>', Instance of 'Future<Post>', Instance of 'Future<Post>'] Commented Apr 12, 2022 at 18:04
  • @IvoBeckers you are actually right, if I print(futurePosts) I get Instance of 'Future<List<Post>>'. The null appears to actually come in the FutureBuilder itself, when I print(snapshot.data), so it appears as if the snapshot itself is the issue? Perhaps I'm using it incorrectly. Commented Apr 12, 2022 at 18:05

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.