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.
notifyListeners()
are not waiting for thefetch
to complete
await FirebaseFirestore.instance
.collection("Users")
.doc(FirebaseAuth.instance.currentUser!.uid)
.get()
.then((value) {
userName = (value.data()?[' uname'] ?? "Default userName");
print(userName);
notifyListeners();