【问题标题】:FutureBuilder Completely UnresponsiveFutureBuilder 完全没有反应
【发布时间】:2021-06-20 22:29:54
【问题描述】:

我的流程如下。屏幕只有两个元素 - TextFormField 和 ElevatedButton。

  1. 从用户那里获取电子邮件地址
  2. 用户点击按钮
  3. 按钮验证输入,然后
  4. 调用 FutureBuilder,它
  5. 尝试从 REST API 获取客户端记录
  6. 重定向到适当的路线

这是我的第一个 Flutter/Dart 程序仅供参考,所以我可能会犯一个初学者的错误。

问题:FutureBuilder 的第一行没有执行。没有错误,没有消息,什么都没有。为什么会发生这种情况?

用户输入邮箱地址,点击按钮,fetchClientInfo函数被执行,返回一个Future<ClientInfo>,就是这样。

你能帮忙吗?

@override
Widget build(BuildContext context) {
  final _formKey = GlobalKey<FormState>();

  return Scaffold(
      appBar: AppBar(
        title: Text("Register Profile"),
      ),
      body: Form(
          key: _formKey,
          child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Padding(
                    padding: EdgeInsets.all(20),
                    child: TextFormField(
                      controller: emailController,
                      validator: (email) {
                        if (email.isEmpty) {
                          return 'Please enter your email address.';
                        } else if (!EmailValidator.validate(email)) {
                          return 'Please enter a valid email address.';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        border: new UnderlineInputBorder(borderSide: new BorderSide(color: Colors.red)),
                        labelText: 'Email',
                        hintText: 'Enter your email address',
                        contentPadding: EdgeInsets.all(20.0),
                      ),
                    )),
                ElevatedButton(
                    onPressed: () => {
                          if (_formKey.currentState.validate())
                            {
                              FutureBuilder<ClientInfo>(
                                future: fetchClientInfo(emailController.text),
                                builder: (BuildContext context, snapshot) {
                                  print("here");
                                  if (snapshot.data.outcome) {
                                    return Text("main screen");
                                  } else if (!snapshot.data.outcome) {
                                    Navigator.push(
                                        context,
                                        MaterialPageRoute(
                                            builder: (context) =>
                                                RegisterNewUser(emailAddress: emailController.text)));
                                  } else if (snapshot.hasError) {
                                    return Text("${snapshot.error}");
                                  }

                                  // Show a spinner
                                  return CircularProgressIndicator();
                                },
                              )
                            }
                        },
                    child: Text(
                      "Check Email",
                    ))
              ])));
}
Future<ClientInfo> fetchClientInfo(String emailAddress) async {
  var url = Uri.https(APIAccess.baseAPIURL, APIAccess.pathToClientAPI, {
    'client_id': '$emailAddress',
    'action': 'info',
    'key': '${APIAccess.key}'
  });

  final response = await http.get(url);

  if (response.statusCode == 200) {
    return ClientInfo.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load album');
  }
}

【问题讨论】:

  • 你能显示 fetchClientInfo 吗?
  • @LOLWTFasdasdasdad 已更新,谢谢。

标签: flutter dart flutter-futurebuilder


【解决方案1】:

你错过了几件事:

  1. return 语句(在您的 lambda 中,您正在创建一个 FutureBuilder,但它并未在任何地方使用)
if(true) {
  return SizedBox.shrink();
}
  1. 正确的 lambda 语法(好吧,从技术上讲它是正确的,但它没有做你想要的):https://dart.dev/guides/language/language-tour#anonymous-functions
// that's how compiler sees it
Map<dynamic, dynamic> Function() foo = () => {
  
};

你所做的让我想起了 javascript,但在 dart lambdas 中看起来有点不同

return Button(
  onTap: () => doStuff(),
);

return Button(
  onTap: () {
    doStuff();
  }
);

// and if you want to return a value from block lambda
return Builder(
  builder: (context) {
    return SizedBox.shrink();
  }
);
  1. 点击渲染小部件 在处理点击事件时,最好将调用重定向到处理业务逻辑的组件,并且只监听小部件中的当前状态。

您想了解的是状态管理。该主题非常自以为是,因此您必须自己选择适合您的解决方案。 https://flutter.dev/docs/development/data-and-backend/state-mgmt

我自己喜欢使用稍微修改过的 bloc 版本。你可以在这里找到“原版”:https://pub.dev/packages/flutter_bloc

如果涉及到状态管理,一个新的事实标准是Riverpod

如果您只想让您的代码正常工作,请执行以下操作:

class Demo extends StatefulWidget {
  @override
  _DemoState createState() => _DemoState();
}

class _DemoState extends State<Demo> {

  Future<ClientInfo?> clientInfo = Future.value(null);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: () {
            setState(() {
              clientInfo = fetchClientInfo(emailController.text);
            });
          },
          child: _buildButtonContent(),
        ),
        FutureBuilder<ClientInfo>(
          initialData: null,
          future: clientInfo,
          builder: (BuildContext context, snapshot) {
            if (snapshot.data == null) {
              return SizedBox.shrink();
            } else {
              return Text(snapshot.data.toString());
            }
          },
        )
      ],
    );
  }
}

【讨论】:

  • 我确实认为退货存在问题,但无法弄清楚原因。在注释掉最后一个微调器返回时,我看到一个没有返回的警告,尽管我可以在那里看到两个。我做错了什么?
  • 好的,我现在明白了。但仍不清楚如何返回 FutureBuilder 的结果。
  • 我已经更新了答案,看看sn-p。它无论如何都不是完美的,但它会起作用。理想情况下,您希望使用状态管理实用程序,例如 Riverpod 或 BLOC。
猜你喜欢
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 2015-12-20
  • 2011-04-25
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2016-12-11
相关资源
最近更新 更多