Futurebuilder snapshot has no data

Issue

CollectionReference users = FirebaseFirestore.instance.collection('Users');
  FirebaseAuth auth = FirebaseAuth.instance;
  String uid = FirebaseAuth.instance.currentUser!.uid.toString();
  var userData;
  var dbFuture;

  @override
  void initState() {
    dbFuture = getData();
    super.initState();
  }

  Future getData() async {
    final String uid = FirebaseAuth.instance.currentUser!.uid.toString();
    final DocumentSnapshot doc = await users.doc(uid).get();
    users.doc(uid).get().then((DocumentSnapshot doc) {
      userData = doc.data();
      print(doc.data());
    });
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        body: FutureBuilder(
            future: dbFuture,
            builder: (context, snapshot) {
              if (snapshot.connectionState != ConnectionState.done) {
                return Container(
                  child: Text('waiting'),
                );
              }
              if (!snapshot.hasData) {
                return Container(
                  child: Text('error'),
                );
              }
              final data = snapshot.data;
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(userData['displayName']),
                    ElevatedButton(
                        onPressed: FirebaseAuth.instance.signOut,
                        child: Text("Log out"))
                  ],
                ),
              );
            }),
      );

I’m new in Flutter and trying to make an application for managing an academy.

I successfully saved the data at Firestore Cloud, and I can read them with

      print(doc.data());

Now I want to build Profile page with those data, so I used Futurebuilder.

But snapshot always has no data.

I read documents as well, but still have no idea.

Solution

To get your data from Firebase and display them in your widgets, you have two ways, but you have to choose only one according to your needs.

With FutureBuilder()

This code will call your database and load the info you request at each build and at each setState() (responsible for updating your interface content). It could be useful for some data types, but in your case your redundant Firebase calls could cost you.

CollectionReference users = FirebaseFirestore.instance.collection('Users');
  final auth = FirebaseAuth.instance;
  late final uid = auth.currentUser!.uid;

@override
  Widget build(BuildContext context) => Scaffold(
        body: FutureBuilder(
                future: users.doc(uid).get(),
                builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return Container(
                      child: Text('waiting'),
                    );
                  }
                  if (!snapshot.hasData) {
                    return Container(
                      child: Text('error'),
                    );
                  }

                  return Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(snapshot.data!['some_data']),
                        Text(auth.currentUser?.displayName ?? 'user have no name'),
                        ElevatedButton(
                            onPressed: auth.signOut,
                            child: Text("Log out"))
                      ],
                    ),
                  );
                }),
      );

In the initState()

When using initState(), the code inside is called only once. To refresh the content, you will have to call getData() manually (in a setState() for example)

CollectionReference users = FirebaseFirestore.instance.collection('Users');
  final auth = FirebaseAuth.instance;
  late final uid = auth.currentUser!.uid;

  String? someData;

  @override
  void initState() {
      getData();
    super.initState();
  }

  Future<void> getData() async {
    users.doc(uid).get().then((doc) {
      someData = doc['some_data'];
    });
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(someData ?? 'no data'),
            Text(auth.currentUser?.displayName ?? 'user have no name'),
            ElevatedButton(
                onPressed: auth.signOut,
                child: Text("Log out"))
          ],
        ),
      ),
    );

Finally, if your users authenticate, you can use auth.currentUser?.displayName and auth.currentUser!.updateDisplayName('new name') to simply get and change your users’ names.

Answered By – Matt

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *