Reputation: 262
I'm having a problem in my home_screen.dart file. I have a method called pullUserData() that is called in initState() but before pullUserData() is completely finished, the build method in home_screen.dart begins. This results in null values (auth and friendsList) being sent to NavDrawer() and FriendsFeed() in the build method of home_screen.dart.
How can I prevent NavDrawer() and FriendsFeed() from being called in the build method before initState() is completely finished? Should I use FutureBuilder?
User_data.dart handles gets the values for auth and friendsList.
home_screen.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:mood/components/friends_feed.dart';
import 'package:mood/components/nav_drawer.dart';
import 'package:mood/services/user_data.dart';
class LandingScreen extends StatefulWidget {
static const String id = 'landing_screen';
@override
_LandingScreenState createState() => _LandingScreenState();
}
class _LandingScreenState extends State<LandingScreen> {
FirebaseAuth auth;
List<dynamic> friendsList;
@override
void initState() {
super.initState();
pullUserData();
}
Future<void> pullUserData() async {
UserData userData = UserData();
await userData.getUserData();
auth = userData.auth;
friendsList = userData.friendsList;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Mood'),
centerTitle: true,
),
drawer: NavDrawer(auth),
body: FriendsFeed(friendsList),
);
}
}
user_data.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class UserData {
final FirebaseAuth _auth = FirebaseAuth.instance;
User _currentUser;
String _currentUserUID;
List<dynamic> _friendsList;
FirebaseAuth get auth => _auth;
User get currentUser => _currentUser;
String get currentUserUID => _currentUserUID;
List<dynamic> get friendsList => _friendsList;
Future<void> getUserData() async {
getCurrentUser();
getCurrentUserUID();
await getFriendsList();
}
void getCurrentUser() {
_currentUser = _auth.currentUser;
}
void getCurrentUserUID() {
_currentUserUID = _auth.currentUser.uid;
}
Future<void> getFriendsList() async {
await FirebaseFirestore.instance
.collection("Users")
.doc(_currentUserUID)
.get()
.then((value) {
_friendsList = value.data()["friends"];
});
}
}
Upvotes: 0
Views: 1081
Reputation: 73
There are couple of problems in your code but it will work.
Firstly, if you want to set value of your friendslist during build, you have to use setState like this:
setState(() {
friendsList = userData.friendsList;
});
And if you want to wait until pullUserData() finish, you are looking for something called splash screen, but in your problem, you are waiting only for body to be build so I will recommend to use progress indicator in your scaffold like this:
return Scaffold(
appBar: Bars.menuAppBar('Devices'),
drawer: DrawerMenu(),
backgroundColor: ColorThemes.backgroundColor,
body: _loading
? Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
Colors.blue), //choose your own color
))
: FriendsFeed(friendsList)
);
You can see that I used _loading variable. You will have to define it before your initState() like
bool _loading = true;
Then after you set your friendsList inside of your pullUserData() function, change _loading to false inside of setState just like this:
setState(() {
friendsList = userData.friendsList;
_loading = false;
});
Upvotes: 1