skip to Main Content

I’m trying to display a document field value from firestore and want to display it on other pages using the provider.

This is my code inside the provider file:

class UserState extends ChangeNotifier {
  
  String userName = 'default error';

   Future<void> getName() async {
    await FirebaseFirestore.instance
        .collection("Users")
        .doc(FirebaseAuth.instance.currentUser!.uid)
        .get()
        .then((value) {
      userName = (value.data()?[' uname'] ?? "Default userName");
      print(userName);
    });
    notifyListeners();
  }
}

Here the correct userName value is getting printed using print statement, but when I try to pass it through the provider it is showing the initialized string value default error which I provided for null safety.
This is the screen where I want to display the variable userName :


class testscreen extends StatefulWidget {
  const testscreen({Key? key}) : super(key: key);
  _testscreenState createState() => _testscreenState();
}

class _testscreenState extends State<testscreen> {
  @override
  Widget build(BuildContext context) {

    Provider.of<UserState>(context, listen: false).getName();
    final String name = Provider.of<UserState>(context).userName;
    return Scaffold(body: Text(name));
  }
}

How can I show the right value instead of initialized value for userName?What’s wrong with my code?

2

Answers


  1. notifyListeners doesn’t wait to finish the fetch. You can try

      void getName() {
        FirebaseFirestore.instance
            .collection("Users")
            .doc(FirebaseAuth.instance.currentUser!.uid)
            .get()
            .then((value) {
          userName = (value.data()?[' uname'] ?? "Default userName");
          print(userName);
          notifyListeners();
        });
      }
    

    Or

      Future<void> getName() async {
        final value = await FirebaseFirestore.instance
            .collection("Users")
            .doc(FirebaseAuth.instance.currentUser!.uid)
            .get();
        userName = (value.data()?[' uname'] ?? "Default userName");
        notifyListeners();
      }
    

    I will prefer using Consumer widget for this case.


    You can also use initState to call the method.

    class testscreen extends StatefulWidget {
      const testscreen({Key? key}) : super(key: key);
      _testscreenState createState() => _testscreenState();
    }
    
    class _testscreenState extends State<testscreen> {
      @override
      void initState() {
        super.initState();
         Provider.of<UserState>(context, listen: false).getName();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Consumer<UserState>(// using consumer 
            builder: (context, value, child) {
              return Text(value.userName);
            },
          ),
        );
      }
    }
    

    Also you can call the method on constructor,

    class UserState extends ChangeNotifier {
      String userName = 'default error';
      UserState() {
        getName();
      }
      Future<void> getName() async {
        await Future.delayed(Duration(seconds: 1));
        userName = "Default userName";
        notifyListeners();
      }
    }
    
    Login or Signup to reply.
  2. There are some fixes in the code.

    1. notifyListeners() are not waiting for the fetch to complete
     await FirebaseFirestore.instance
            .collection("Users")
            .doc(FirebaseAuth.instance.currentUser!.uid)
            .get()
            .then((value) {
          userName = (value.data()?[' uname'] ?? "Default userName");
          print(userName);
          notifyListeners(); 👈 Try adding the notifyListeners() here
        });
      }
    
    1. Remove the provider() call from within the bluid method
    class testscreen extends StatefulWidget {
      const testscreen({Key? key}) : super(key: key);
      _testscreenState createState() => _testscreenState();
    }
    
    class _testscreenState extends State<testscreen> {
      @override
      void initState() {
        super.initState();
         Provider.of<UserState>(context, listen: false).getName();👈 Call getName here
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(body: Text( Provider.of<UserState>(context).userName)); 👈 Call it this way
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search