在我的应用程序的配置文件页面中,我想使用async / await函数将将来的对象列表从Firebase集合保存到变量(myRecipes)。根据结果列表,我想显示不同的小部件(使用ifHasRecipes())-如果列表结果为null或为空,则我想显示一个文本小部件,否则,我想使用一个来显示列表中的对象列表视图生成器(FavoritesHomePage类)。
class Profile extends StatefulWidget {
final FirebaseAuth _auth = FirebaseAuth.instance;
@override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
List<Recipe> myRecipes;
Future<List<Recipe>> getUserRecipes(UserData userData) async {
return myRecipes = await DatabaseService().findUserRecipes(userData.uid);
}
Widget ifHasRecipes() {
if (myRecipes != null && myRecipes != []) {
return FavoritesHomePage(
recipes: myRecipes, scrollDirection: Axis.vertical, title: 'Your recipes',);
} else {
return Text('You have no favorites yet');
}
}
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return StreamBuilder<UserData>(
stream: DatabaseService(uid: user.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData userData = snapshot.data;
getUserRecipes(userData);
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
//widgets using userData
ifHasRecipes(),
],
),
),
);
} else {
return Scaffold(
body: Center(
child: SpinKitRipple(),),
);
}
});
}
}
如何使此代码同步?我想运行getUserRecipes(),完成后根据结果返回不同的小部件。
如果我进行热重装,代码将按我希望的方式“工作”,但是有时当我通过综合浏览器小部件导航到此个人资料页面时,返回变量myRecipes的async / await函数在如果已构建ifHasRecipes(),则myRecipes为null(即使不应该如此)...希望这不会造成混淆,对不起。
答案 0 :(得分:0)
如果我正确理解了代码,解决方案是在将来解决时,通过向setState((){});
方法中添加getUserRecipes()
来重建窗口小部件:
Future<void> getUserRecipes(UserData userData) async {
myRecipes = await DatabaseService().findUserRecipes(userData.uid);
setState((){});
}
(如果您将值分配给状态,则不必返回该值,而是直接访问它。)
顺便说一句,您可以使用三元运算符(或只是常规条件)来执行条件UI。放置它而不是ifHasRecipes(),
:
(myRecipes != null && myRecipes != []) ?
FavoritesHomePage(
recipes: myRecipes, scrollDirection: Axis.vertical, title: 'Your recipes',)
: Text('You have no favorites yet')
如果遇到此错误,请在pubspec.yaml中将最低SDK版本提高到2.6.0
答案 1 :(得分:0)
在这种情况下,您可以使用FutureBuilder
,在这种情况下,您将拥有不同的状态,就像StreamBuilder
,并且可以根据状态显示不同的小部件,直到Future解决。并且您有数据。
我已经对您的代码进行了一些重构,以使其可以与FutureBuilder一起使用,并且我将其更改为“无状态”,在这种情况下,它将显示CircularProgressIndicator
,直到Future解决为止,它还将处理错误和数据不足。
class Profile extends StatelessWidget {
const Profile({Key key}) : super(key: key);
Future<List<Recipe>> getUserRecipes(UserData userData) async {
return await DatabaseService().findUserRecipes(userData.uid);
}
Widget ifHasRecipes(List<Recipe> myRecipes) {
if (myRecipes != null && myRecipes != []) {
return FavoritesHomePage(
recipes: myRecipes,
scrollDirection: Axis.vertical,
title: 'Your recipes',
);
} else {
return Text('You have no favorites yet');
}
}
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return StreamBuilder<UserData>(
stream: DatabaseService(uid: user.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Scaffold(
body: SafeArea(
child: FutureBuilder(
future: getUserRecipes(snapshot.data),
builder: (context, futureSnapshot) {
if (futureSnapshot.hasError)
return Text('Error: ${futureSnapshot.error}');
switch (futureSnapshot.connectionState) {
case ConnectionState.none:
return Center(child: CircularProgressIndicator());
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:{
if (futureSnapshot.hasData) {
List<Recipe> myRecipes = futureSnapshot.data;
return Column(
children: <Widget>[
//widgets using userData
ifHasRecipes(myRecipes),
],
);
}
return Text('There\'s no available data.');
}
}
return null;
},
),
),
);
} else {
return Scaffold(
body: Center(
child: SpinKitRipple(),
),
);
}
},
);
}
}