如何在 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)

使用 Mockito 的 FutureBuilder 快照数据为空 - Flutter