如何在 FutureBuilder Flutter 中停止循环 SetState
Posted
技术标签:
【中文标题】如何在 FutureBuilder Flutter 中停止循环 SetState【英文标题】:how stop looping SetState inside FutureBuilder Flutter 【发布时间】:2021-08-15 12:11:17 【问题描述】:我有构建小部件。在构建内部,我调用 FutureBuilder 从 API 加载数据。所以我在 FutureBuilder 中添加了 setState 。当我单击编辑按钮将某些内容添加到文本表单中时,这对屏幕进行了不寻常的刷新。我想将未来移出... initState 。这样做的正确方法是什么??
我的代码:
class _ProfileState extends State<Profile>
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final Color blue = Color(0xFF010611);
BoxApi boxApi = BoxApi();
UserApi userApi = UserApi();
@override
void initState()
super.initState();
myFocusNode = FocusNode();
telephoneNode = FocusNode();
adresseNode = FocusNode();
emailNode = FocusNode();
passwordNode = FocusNode();
_isHidden = true;
@override
Widget build(BuildContext context)
Size size = MediaQuery.of(context).size;
return SafeArea(
/* minimum: const EdgeInsets.only(
top: 20.0, right: 5.0, left: 5.0, bottom: 10.0),*/
child: Center(
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Color(0xFFF6F7F8),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: FutureBuilder<User>(
future: boxApi.getUser(),
builder: (context, snapshot)
// ignore: missing_return
print(snapshot.data);
switch (snapshot.connectionState)
case ConnectionState.none:
return Text('no connection');
case ConnectionState.active:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
break;
case ConnectionState.done:
if (snapshot.hasError)
return Text('error');
else if (snapshot.hasData)
// String price = snapshot.data['body'].;
// print("$snapshot.data");
return Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
padding: EdgeInsets.only(top: 16),
width: MediaQuery.of(context).size.width,
height:
MediaQuery.of(context).size.height / 4,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.white60,
blurRadius: 15.0,
offset: Offset(0.0, 0.75))
],
gradient: LinearGradient(
begin: Alignment(0.5, 0.85),
end: Alignment(0.48, -1.08),
colors: [
const Color(0xFF0B0C3A),
const Color(0xFF010611),
],
stops: [
0.0,
0.5,
],
),
//color: blue,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(32),
bottomLeft: Radius.circular(32))),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 30,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"$snapshot.data.name",
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight:
FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(
"$snapshot.data.phone",
style: TextStyle(
color: Colors.white60,
fontSize: 18,
//fontWeight: FontWeight.w300
),
),
])
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Container(
margin: EdgeInsets.symmetric(
vertical: 10),
width: size.width * 0.4,
child: ElevatedButton(
/*onPressed: () => [
modifyUserName(),
// modifyUserEmail(),
// modifyUserAdress()
],*/
onPressed: ()
editUserProfile();
// modifyUserEmail();
,
child: Text('Enregistrer'),
style:
ElevatedButton.styleFrom(
primary: Colors.transparent,
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(
20),
side: BorderSide(
color: Colors
.white)),
),
)),
SizedBox(
width: 20,
),
],
)
],
),
),
Container(
height: MediaQuery.of(context).size.height /
1.5,
// padding: EdgeInsets.only(
// top: 32,
// ),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Container(
width: size.width * 0.94,
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
left: 10,
right: 10,
bottom: 20,
top: 20),
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(
'Votre nom :',
style: TextStyle(
color: Color(
0xFF4053FCF),
fontSize: 16,
fontWeight:
FontWeight
.w600),
),
IconButton(
icon: Icon(
CommunityMaterialIcons
.pencil,
color: Colors
.grey,
),
onPressed: ()
myFocusNode
.requestFocus();
setState(()
enableup =
true;
);
)
],
),
TextFormField(
controller:
_nameController,
enabled: enableup,
focusNode:
myFocusNode,
enableInteractiveSelection:
false,
keyboardType:
TextInputType
.text,
decoration: InputDecoration(
hintText:
"$snapshot.data.name",
hintStyle: TextStyle(
color: Colors
.grey,
fontSize:
14.0)),
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(
'N° Téléphone :',
style: TextStyle(
color: Color(
0xFF4053FCF),
fontSize: 16,
fontWeight:
FontWeight
.w600),
),
/* IconButton(
icon: Icon(
CommunityMaterialIcons
.pencil,
color: Colors
.grey,
),
onPressed: ()
telephoneNode
.requestFocus();
setState(()
enabletel =
true;
);
)*/
],
),
TextFormField(
enabled: false,
focusNode:
telephoneNode,
enableInteractiveSelection:
false,
keyboardType:
TextInputType
.text,
decoration: InputDecoration(
hintText:
"$snapshot.data.phone",
hintStyle: TextStyle(
color: Colors
.grey,
fontSize:
14.0)),
),
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(
'Adresse :',
style: TextStyle(
color: Color(
0xFF4053FCF),
fontSize: 16,
fontWeight:
FontWeight
.w600),
),
IconButton(
icon: Icon(
CommunityMaterialIcons
.pencil,
color: Colors
.grey,
),
onPressed: ()
adresseNode
.requestFocus();
setState(()
enableadress =
true;
);
)
],
),
TextFormField(
enabled: enableadress,
controller:
_adressController,
focusNode:
adresseNode,
enableInteractiveSelection:
false,
keyboardType:
TextInputType
.text,
decoration: InputDecoration(
hintText:
"$snapshot.data.adress",
hintStyle: TextStyle(
color: Colors
.grey,
fontSize:
14.0)),
),
else
return Text('No Data');
break;
default:
return Container();
break;
如何在 initState 中运行 getUser() 以防止 FutureBuilder 和 setState 之间循环?
【问题讨论】:
您好,如果您确实需要使用 setState,但又不想刷新整个页面,只需将您的 FutureBuilder 包装在 StatefullBuilder 中即可。 builder的参数是什么? 未定义命名参数“child”。 @Edivaldo Marco 查看下面的例子 【参考方案1】:类似这样的:
StatefulBuilder(
builder: (context, setState2) => FutureBuilder<User>(...))
并将 FutureBuilder 中的任何 setState 替换为 setState2,这样当你使用 setState2 时,他只会刷新 FutureBuilder 而不是整个页面。
【讨论】:
我实施了您的解决方案。问题依然存在。当我点击编辑按钮==>重新加载所有屏幕。我只想引用输入文本。 @Edivaldo Marco 当你点击这个函数onPressed时重新加载整个屏幕: () editUserProfile(); // 修改用户邮箱(); 对吗?【参考方案2】:你不应该在 build 中调用 setState,原因很简单:setState 会导致 build,而 build 调用 setState
您可以将未来移出构建并在 initState 中调用它。
移动框Api.getUser();像这样初始化状态:
void initState()
super.initState();
future = boxApi.getUser();
效果很好
【讨论】:
以上是关于如何在 FutureBuilder Flutter 中停止循环 SetState的主要内容,如果未能解决你的问题,请参考以下文章
在这种情况下,如何在 Flutter 中正确实现 FutureBuilder?
我如何在 FutureBuilder Widget 的构建器函数中等待 - Flutter
flutter - bloc - 我如何在我的 Ui 中使用 FutureBuilder 来正确实现 Bloc 架构
Flutter:防止抽屉在 FutureBuilder 内滑动时始终刷新
Flutter - 如何更新用于构建 ListView 的 Future/List 的状态(或值?)(通过 FutureBuilder)