我有下面的代码,其想法是,当用户登录时,他们被推送到该页面(“仪表板”)。我正在尝试使用initState
来使应用程序运行函数takenSurvey2()
,该函数然后为布尔takenSurvey
创建一个值。这来自查询Cloud Firestore。
布尔值takenSurvey
然后将在堆栈的“位置”小部件中使用,以确定要向用户显示的图标(如果用户未参加调查(即takenSurvey
=否)他们会看到一个“新”图标。
但是,当前发生的情况是,当用户登录并加载页面并显示错误图标时,该小部件认为takenSurvey
的值不为true或false。但是,当我创建一个任意按钮并使用OnPressed
打印takenSurvey
的值时,它在控制台中显示为“ false”。如我所料,当我热重新加载仪表板页面时,错误图标变成了“新”图标-为什么它不立即这样做?
我不确定自己在做什么,以及为什么小部件看不到takenSurvey
的值,即使takenSurvey2()
已在initState
中运行,并且我已经将它包装在Builder
小部件中了吗?
class Dashboard extends StatefulWidget {
static const String id = 'dashboard';
@override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final _auth = FirebaseAuth.instance;
var userid;
String surveyName;
bool takenSurvey;
String title;
@override
void initState() {
super.initState();
getCurrentUser();
getUserID();
currentSurveyName();
takenSurvey2();
}
void takenSurvey2() async {
final snapShot = await Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.get();
if (snapShot.exists) {
takenSurvey = true;
} else {
takenSurvey = false;
}
}
@override Widget build(BuildContext context) {
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width * 0.9,
child: SquareButton(
buttonTitle: "",
fontSize: 36,
onPressed: () async {
final snapShot = await Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.get();
if (snapShot.exists) {
_alreadyCompletedSurveyError();
} else if (surveyName.isEmpty)
_otherError();
else {
return Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new TestSurvey(surveyName)));
}
}),
),
Positioned(
right: 30,
top: 20,
child: Builder(builder: (context) {
if (takenSurvey == false) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (takenSurvey == true) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else
return Icon(
MaterialIcons.error,
size: 48,
color: Color(0xff303841),
);
}),
),
Container(
child: Text('Latest Survey',
style: TextStyle(
color: Colors.white,
fontSize: 36,
fontFamily: "Roboto")),
答案 0 :(得分:1)
首先请注意,小部件的build()方法是同步的,因此它可以在Flutter需要时立即运行,并且可以在框架需要时被调用多次,而不必调用一次
其次,您的takedSurvey没有默认值,并且初始化为空
那么接下来会发生什么:
按下按钮或进行热重装怎么办?如果您在例行程序完成后进行了此操作(如果您之前按过该按钮,则会看到此情况
)热重装会重建树,最后您可以在屏幕上看到数据
对代码的第一个最简单的解决方法是在void takeSurvey2()例程的结尾处调用setState()-这将重建您的小部件(flutter重新运行build())
void takenSurvey2() async {
final snapShot = await Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.get();
if (snapShot.exists) {
takenSurvey = true;
} else {
takenSurvey = false;
}
setState((){});
}
当然,您需要处理takenSurvey == null-您需要向用户显示“正在加载”指示器,因为您执行了一些异步操作,但用户不知道发生了什么
第二种更方便的方法是使用FutureBuilder(完全由您来完成下一个代码片段以使其起作用,可以随意在评论中提问)
FutureBuilder(
future: Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.get(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.exists) {
_alreadyCompletedSurveyError();
} else if (surveyName.isEmpty)
_otherError();
... more code
} else {
// show loading
}
},
)
最后一条建议-您需要学习状态管理以及如何将逻辑与小部件分开。
您将以开发人员的方式使用它。
从这里开始 https://flutter.dev/docs/development/data-and-backend/state-mgmt
答案 1 :(得分:-1)
您可以尝试在initstate中添加异步功能吗?
@override
void initState() {
super.initState();
test();
}
void test() async {
await getCurrentUser();
await getUserID();
await currentSurveyName();
await takenSurvey2();
}