I thought this was going to be far easier than it turned out but I have a collection called 'USER_TABLE' with userID, email, first name and lastName.
I want to retrieve the firstName from the database and then use it in a Text widget
I am printing the firstName for debug purposes and im getting the right value but its displaying in my app as Instance of 'Future
Any ideas as to what im doing wrong? Getting no errors currently
Thanks
CODE:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:moodful/components/authentication_service.dart';
import 'package:moodful/components/background.dart';
import 'package:moodful/Screens/Login/login_screen.dart';
class HomeScreen extends StatefulWidget {
HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
// This size provide us total height and width of our screen
var firstName = getData();
//return Scaffold(
return BackgroundLogoRight(
text: "Home",
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 10,
child: Text(
"$firstName \n\n "
"Glad you're back, please enter a mood for today.\n\n "
"Be sure to check the insights page for the most up to date mood analysis\n\n"
"The more you know the more control you have",
style: TextStyle(color: Colors.black, fontSize: 15),
textAlign: TextAlign.center,
),
),
],
),
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen(); // change to return something sensible
},
),
);
}, // handle your image tap here
child: Image.asset(
"assets/images/recordMoodLogo.jpg",
width: size.width * 0.5,
fit: BoxFit.cover, // this is the solution for border
height: 110.0,
),
),
],
),
),
],
),
);
}
getData() async {
var currentUser = FirebaseAuth.instance.currentUser;
DocumentSnapshot variable = await FirebaseFirestore.instance
.collection('USER_TABLE')
.doc(currentUser!.uid)
.get();
print(variable['firstName']);
return variable['firstName'];
}
}
CodePudding user response:
When fetching data from Firebase or from any other source, that will be done in an asynchronous way, therefore it will take some time until the data is fetched. In Flutter, you can use a widget called FutureBuilder for these asynchronous calls. For example:
class _HomeScreenState extends State<HomeScreen> {
Future<DocumentSnapshot<Map<String, dynamic>>>? _fetchedData;
@override
void initState() {
super.initState();
_fetchedData = getData();
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
FutureBuilder(
future: _fetchedData,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasData) {
return BackgroundLogoRight(
text: "Home",
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 10,
child: Text(
"${snapshot.data!.data()!["firstname"]} \n\n "
"Glad you're back, please enter a mood for today.\n\n "
"Be sure to check the insights page for the most up to date mood analysis\n\n"
"The more you know the more control you have",
style: TextStyle(color: Colors.black, fontSize: 15),
textAlign: TextAlign.center,
),
),
],
),
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen(); // change to return something sensible
},
),
);
}, // handle your image tap here
child: Image.asset(
"assets/images/recordMoodLogo.jpg",
width: size.width * 0.5,
fit: BoxFit.cover, // this is the solution for border
height: 110.0,
),
),
],
),
),
],
),
);
}
else {return CircularProgressIndicator();}
},
);
}
Future<DocumentSnapshot<Map<String, dynamic>>> getData() async {
var currentUser = FirebaseAuth.instance.currentUser;
return await FirebaseFirestore.instance
.collection('USER_TABLE')
.doc(currentUser!.uid)
.get();
}
The getData() method will return the data inside the userid document and then using the FutureBuilder widget you can display the name of the user. Since this is asynchronous, it will be in the waiting state so the circularprogressindicator will appear and then it will be in the completed state when the data is returned. Also obtain the future in the initState
The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.
Check:
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
