Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting user properties from Firestore in Flutter app

I am trying to get several details from the collection "users" (eg, name, surname, nickname) stored in Firestore with the function getUserData() to pass them to other classes through the constructor. The parenthesis in getUserData() is highlighted, pointing to this error message:

1 positional argument expected by 'getUserData', but 0 found.

If I put name as getUserData(name), it says Undefined name 'name'.

What am I missing here?

class AuthWrapper extends StatelessWidget {
  const AuthWrapper({super.key});
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasData && snapshot.data != null) {
          String eMail = snapshot.data!.email.toString();
          String Name = getUserData().toString(); // πŸ‘ˆ PROBLEM HERE
          return AnApp(forUser1: eMail, forUser2: Name);
        } else {
          return const LogIn();
        }
      },
    );
  }
}

Future<void> getUserData(String name) async {
  User? user = FirebaseAuth.instance.currentUser;
  if (user != null) {
    DocumentSnapshot<Map<String, dynamic>> snapShot = await FirebaseFirestore.instance.collection('users').doc(user.uid).get();
    if (snapShot.exists) {
      var datA = snapShot.data();
      String name = datA?['name'];
      String surname = datA?['surname'];
      String nickname = datA?['nickname'];
    }
  }
}
like image 494
Gery Avatar asked Dec 03 '25 21:12

Gery


2 Answers

Your getUserData function expects a name parameter, but you're not passing anything in when you call it here:

String Name = getUserData().toString();

So that's what the error message tells you: it expects you to pass a parameter when you call getUserData(), but you are not meeting that expectation.

It looks like getUserData does not actually use the name parameter though, so you can just remove it:

Future<void> getUserData() async {
  ...

That will solve the first problem in your code, and the initial error will disappear.


Currently your `getUserData` doesn't actually return any value, as you declare it as Future<void>. More likely, you want to actually return the user name from getUserData, which means it'll look like this:

    //   πŸ‘‡ Indicates that we return a string value at some point in the future
Future<String> getUserData() async {
  User? user = FirebaseAuth.instance.currentUser;
  if (user != null) {
    DocumentSnapshot<Map<String, dynamic>> snapShot = await FirebaseFirestore.instance.collection('users').doc(user.uid).get();
    if (snapShot.exists) {
      var datA = snapShot.data();
      String name = datA?['name'];
      String surname = datA?['surname'];
      String nickname = datA?['nickname'];
      return nickname; // πŸ‘ˆ For now, let's return just the nickname
    }
  }
  return "Unknown user"; // πŸ‘ˆ default value if no user is signed in or no document exists for them
}

If you want to return more than just a single value, you can stuff the names into a map, or create a custom type for the user data.


Note again that this returns a Future<String>, not just a String. This means that your getUserData().toString() still won't give you the value you want, as it may not be available yet.

To learn how to deal with async values like this in Flutter, I recommend reading Asynchronous programming: futures, async, await. The simplest solution here is to use a FutureBuilder.

like image 157
Frank van Puffelen Avatar answered Dec 05 '25 17:12

Frank van Puffelen


The error happens because of two main issues:

  1. Your function getUserData(String name) expects one argument, but you’re calling it with none ,getUserData().

  2. The function is async, so you can’t call it like a regular method inside build() and immediately use its value.

1. Remove the unnecessary parameter

You don’t need to pass anything to getUserData(), since it already reads the current user from Firebase.
Change the function like this:

Future<Map<String, dynamic>?> getUserData() async {
  User? user = FirebaseAuth.instance.currentUser;
  if (user != null) {
    final snapShot = await FirebaseFirestore.instance
        .collection('users')
        .doc(user.uid)
        .get();

    if (snapShot.exists) {
      return snapShot.data(); // returns {'name': ..., 'surname': ..., 'nickname': ...}
    }
  }
  return null;
}

Now getUserData() returns a Future<Map<String, dynamic>?> that you can await.

2. Use FutureBuilder to wait for Firestore data

Because getUserData() is async, you can’t just call it inside build() β€” you need to wait for the data to load first.
You can do that with a FutureBuilder:

class AuthWrapper extends StatelessWidget {
  const AuthWrapper({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else if (snapshot.hasData && snapshot.data != null) {
          final eMail = snapshot.data!.email!;

          // Fetch Firestore user data
          return FutureBuilder<Map<String, dynamic>?>(
            future: getUserData(),
            builder: (context, userSnapshot) {
              if (userSnapshot.connectionState == ConnectionState.waiting) {
                return const Center(child: CircularProgressIndicator());
              } else if (userSnapshot.hasData && userSnapshot.data != null) {
                final data = userSnapshot.data!;
                final name = data['name'];
                final surname = data['surname'];
                final nickname = data['nickname'];

                return AnApp(
                  forUser1: eMail,
                  forUser2: name,
                  forUser3: surname,
                  forUser4: nickname,
                );
              } else {
                return const Center(child: Text('User data not found.'));
              }
            },
          );
        } else {
          return const LogIn();
        }
      },
    );
  }
}

In short: Change

Future<void> getUserData(String name)

to

Future<Map<String, dynamic>?> getUserData()

and fetch it using a FutureBuilder inside your StreamBuilder.

like image 27
Jashwanth Neela Avatar answered Dec 05 '25 15:12

Jashwanth Neela



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!