Home > Back-end >  Why Provider is not giving the initialized value instead of expected one?
Why Provider is not giving the initialized value instead of expected one?

Time:01-03

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?

CodePudding user response:

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();
  }
}

CodePudding user response:

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();            
  • Related